diff --git a/firetweet.apk?raw=true b/firetweet.apk?raw=true new file mode 100644 index 00000000..8d3da570 Binary files /dev/null and b/firetweet.apk?raw=true differ diff --git a/firetweet.component.common/.gitignore b/firetweet.component.common/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.component.common/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.component.common/build.gradle b/firetweet.component.common/build.gradle new file mode 100644 index 00000000..45f223c6 --- /dev/null +++ b/firetweet.component.common/build.gradle @@ -0,0 +1,45 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile 'com.android.support:support-annotations:22.0.0' + compile 'org.apache.commons:commons-lang3:3.4' + compile project(':firetweet.component.jsonserializer') + compile project(':firetweet.component.querybuilder') + compile project(':firetweet.component.twitter4j') + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.component.common/proguard-rules.pro b/firetweet.component.common/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.component.common/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.component.common/src/androidTest/java/org/getlantern/firetweet/common/ApplicationTest.java b/firetweet.component.common/src/androidTest/java/org/getlantern/firetweet/common/ApplicationTest.java new file mode 100644 index 00000000..a55010c9 --- /dev/null +++ b/firetweet.component.common/src/androidTest/java/org/getlantern/firetweet/common/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.common; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.component.common/src/main/AndroidManifest.xml b/firetweet.component.common/src/main/AndroidManifest.xml new file mode 100644 index 00000000..f0e1935d --- /dev/null +++ b/firetweet.component.common/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/IMediaUploader.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/IMediaUploader.aidl new file mode 100644 index 00000000..fc76c532 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/IMediaUploader.aidl @@ -0,0 +1,29 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2013 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.getlantern.firetweet; + +import org.getlantern.firetweet.model.MediaUploadResult; +import org.getlantern.firetweet.model.ParcelableStatusUpdate; +import org.getlantern.firetweet.model.UploaderMediaItem; + +interface IMediaUploader { + + MediaUploadResult upload(in ParcelableStatusUpdate status, in UploaderMediaItem[] media); + +} diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/IStatusShortener.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/IStatusShortener.aidl new file mode 100644 index 00000000..11dba623 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/IStatusShortener.aidl @@ -0,0 +1,28 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2013 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.getlantern.firetweet; + +import org.getlantern.firetweet.model.ParcelableStatusUpdate; +import org.getlantern.firetweet.model.StatusShortenResult; + +interface IStatusShortener { + + StatusShortenResult shorten(in ParcelableStatusUpdate status, String overrideStatusText); + +} diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/ITimelineSyncHelper.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/ITimelineSyncHelper.aidl new file mode 100644 index 00000000..f783b00c --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/ITimelineSyncHelper.aidl @@ -0,0 +1,28 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2013 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.getlantern.firetweet; + +import org.getlantern.firetweet.model.Account; + +interface ITimelineSyncHelper { + + boolean put(in Account account, String key, long value); + + long get(in Account account, String key); +} diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/Account.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/Account.aidl new file mode 100644 index 00000000..4cb27976 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/Account.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable Account; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/MediaUploadResult.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/MediaUploadResult.aidl new file mode 100644 index 00000000..06f1cd12 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/MediaUploadResult.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable MediaUploadResult; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/MediaUploaderParameter.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/MediaUploaderParameter.aidl new file mode 100644 index 00000000..beff7801 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/MediaUploaderParameter.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable MediaUploaderParameter; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableLocation.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableLocation.aidl new file mode 100644 index 00000000..7b7d8c7e --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableLocation.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable ParcelableLocation; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableStatus.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableStatus.aidl new file mode 100644 index 00000000..37b108fb --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableStatus.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable ParcelableStatus; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableStatusUpdate.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableStatusUpdate.aidl new file mode 100644 index 00000000..0c388b57 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/ParcelableStatusUpdate.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable ParcelableStatusUpdate; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/StatusShortenResult.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/StatusShortenResult.aidl new file mode 100644 index 00000000..0f02dc71 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/StatusShortenResult.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable StatusShortenResult; diff --git a/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/UploaderMediaItem.aidl b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/UploaderMediaItem.aidl new file mode 100644 index 00000000..9fa2c192 --- /dev/null +++ b/firetweet.component.common/src/main/aidl/org/getlantern/firetweet/model/UploaderMediaItem.aidl @@ -0,0 +1,22 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +parcelable UploaderMediaItem; diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/TwidereConstants.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/TwidereConstants.java new file mode 100644 index 00000000..f85574ad --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/TwidereConstants.java @@ -0,0 +1,251 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet; + +import org.getlantern.firetweet.constant.IntentConstants; +import org.getlantern.firetweet.constant.SharedPreferenceConstants; + +/** + * Public constants for both Twidere app and its extensions + * + * @author mariotaku + */ +public interface TwidereConstants extends SharedPreferenceConstants, IntentConstants { + + public static final String APP_NAME = "FireTweet"; + public static final String APP_PACKAGE_NAME = "org.getlantern.firetweet"; + public static final String APP_PROJECT_URL = "https://github.com/getlantern/firetweet"; + public static final String APP_PROJECT_EMAIL = "firetweet@getlantern.org"; + + public static final String LOGTAG = APP_NAME; + + public static final String USER_NICKNAME_PREFERENCES_NAME = "user_nicknames"; + public static final String USER_COLOR_PREFERENCES_NAME = "user_colors"; + public static final String HOST_MAPPING_PREFERENCES_NAME = "host_mapping"; + public static final String MESSAGE_DRAFTS_PREFERENCES_NAME = "message_drafts"; + public static final String SHARED_PREFERENCES_NAME = "preferences"; + public static final String PERMISSION_PREFERENCES_NAME = "app_permissions"; + public static final String SILENT_NOTIFICATIONS_PREFERENCE_NAME = "silent_notifications"; + public static final String TIMELINE_POSITIONS_PREFERENCES_NAME = "timeline_positions"; + public static final String ACCOUNT_PREFERENCES_NAME_PREFIX = "account_preferences_"; + + public static final String TWITTER_CONSUMER_KEY = "GvczyrTHyigPs02D2dstj8Ady"; + public static final String TWITTER_CONSUMER_SECRET = "CUArG9FfhO2ZftXs7MSA3ouZvAPQbdDXRbAj7mvG4SCG5ehMXI"; + public static final String TWITTER_CONSUMER_KEY_2 = "GvczyrTHyigPs02D2dstj8Ady"; + public static final String TWITTER_CONSUMER_SECRET_2 = "CUArG9FfhO2ZftXs7MSA3ouZvAPQbdDXRbAj7mvG4SCG5ehMXI"; + public static final String TWITTER_CONSUMER_KEY_3 = "GvczyrTHyigPs02D2dstj8Ady"; + public static final String TWITTER_CONSUMER_SECRET_3 = "CUArG9FfhO2ZftXs7MSA3ouZvAPQbdDXRbAj7mvG4SCG5ehMXI"; + + public static final String SCHEME_HTTP = "http"; + public static final String SCHEME_HTTPS = "https"; + public static final String SCHEME_CONTENT = "content"; + public static final String SCHEME_TWIDERE = "twidere"; + + public static final String PROTOCOL_HTTP = SCHEME_HTTP + "://"; + public static final String PROTOCOL_HTTPS = SCHEME_HTTPS + "://"; + public static final String PROTOCOL_CONTENT = SCHEME_CONTENT + "://"; + public static final String PROTOCOL_TWIDERE = SCHEME_TWIDERE + "://"; + + public static final String AUTHORITY_USER = "user"; + public static final String AUTHORITY_HOME = "home"; + public static final String AUTHORITY_MENTIONS = "mentions"; + public static final String AUTHORITY_DIRECT_MESSAGES = "direct_messages"; + public static final String AUTHORITY_USERS = "users"; + public static final String AUTHORITY_USER_TIMELINE = "user_timeline"; + public static final String AUTHORITY_USER_MEDIA_TIMELINE = "user_media_timeline"; + public static final String AUTHORITY_USER_FAVORITES = "user_favorites"; + public static final String AUTHORITY_USER_FOLLOWERS = "user_followers"; + public static final String AUTHORITY_USER_FRIENDS = "user_friends"; + public static final String AUTHORITY_USER_BLOCKS = "user_blocks"; + public static final String AUTHORITY_STATUS = "status"; + public static final String AUTHORITY_STATUSES = "statuses"; + public static final String AUTHORITY_DIRECT_MESSAGES_CONVERSATION = "direct_messages_conversation"; + public static final String AUTHORITY_SEARCH = "search"; + public static final String AUTHORITY_MAP = "map"; + public static final String AUTHORITY_USER_LIST = "user_list"; + public static final String AUTHORITY_USER_LIST_TIMELINE = "user_list_timeline"; + public static final String AUTHORITY_USER_LIST_MEMBERS = "user_list_members"; + public static final String AUTHORITY_USER_LIST_SUBSCRIBERS = "user_list_subscribers"; + public static final String AUTHORITY_USER_LIST_MEMBERSHIPS = "user_list_memberships"; + public static final String AUTHORITY_USER_LISTS = "user_lists"; + public static final String AUTHORITY_USERS_RETWEETED_STATUS = "users_retweeted_status"; + public static final String AUTHORITY_SAVED_SEARCHES = "saved_searches"; + public static final String AUTHORITY_SEARCH_USERS = "search_users"; + public static final String AUTHORITY_SEARCH_TWEETS = "search_tweets"; + public static final String AUTHORITY_TRENDS = "trends"; + public static final String AUTHORITY_USER_MENTIONS = "user_mentions"; + public static final String AUTHORITY_ACTIVITIES_ABOUT_ME = "activities_about_me"; + public static final String AUTHORITY_ACTIVITIES_BY_FRIENDS = "activities_by_friends"; + public static final String AUTHORITY_INCOMING_FRIENDSHIPS = "incoming_friendships"; + public static final String AUTHORITY_STATUS_RETWEETERS = "status_retweeters"; + public static final String AUTHORITY_STATUS_FAVORITERS = "status_favoriters"; + public static final String AUTHORITY_STATUS_REPLIES = "status_replies"; + public static final String AUTHORITY_RETWEETS_OF_ME = "retweets_of_me"; + public static final String AUTHORITY_MUTES_USERS = "mutes_users"; + public static final String AUTHORITY_NOTIFICATIONS = "notifications"; + + public static final String QUERY_PARAM_ACCOUNT_ID = "account_id"; + public static final String QUERY_PARAM_ACCOUNT_IDS = "account_ids"; + public static final String QUERY_PARAM_ACCOUNT_NAME = "account_name"; + public static final String QUERY_PARAM_STATUS_ID = "status_id"; + public static final String QUERY_PARAM_USER_ID = "user_id"; + public static final String QUERY_PARAM_LIST_ID = "list_id"; + public static final String QUERY_PARAM_SCREEN_NAME = "screen_name"; + public static final String QUERY_PARAM_LIST_NAME = "list_name"; + public static final String QUERY_PARAM_QUERY = "query"; + public static final String QUERY_PARAM_TYPE = "type"; + public static final String QUERY_PARAM_VALUE_USERS = "users"; + public static final String QUERY_PARAM_VALUE_TWEETS = "tweets"; + public static final String QUERY_PARAM_NOTIFY = "notify"; + public static final String QUERY_PARAM_LAT = "lat"; + public static final String QUERY_PARAM_LNG = "lng"; + public static final String QUERY_PARAM_URL = "url"; + public static final String QUERY_PARAM_NAME = "name"; + public static final String QUERY_PARAM_FINISH_ONLY = "finish_only"; + public static final String QUERY_PARAM_NEW_ITEMS_COUNT = "new_items_count"; + public static final String QUERY_PARAM_RECIPIENT_ID = "recipient_id"; + public static final String QUERY_PARAM_READ_POSITION = "param_read_position"; + public static final String QUERY_PARAM_READ_POSITIONS = "param_read_positions"; + + public static final String DEFAULT_PROTOCOL = PROTOCOL_HTTPS; + + public static final String OAUTH_CALLBACK_OOB = "oob"; + public static final String OAUTH_CALLBACK_URL = PROTOCOL_TWIDERE + "com.twitter.oauth/"; + + public static final int REQUEST_TAKE_PHOTO = 1; + public static final int REQUEST_PICK_IMAGE = 2; + public static final int REQUEST_SELECT_ACCOUNT = 3; + public static final int REQUEST_COMPOSE = 4; + public static final int REQUEST_EDIT_API = 5; + public static final int REQUEST_BROWSER_SIGN_IN = 6; + public static final int REQUEST_SET_COLOR = 7; + public static final int REQUEST_SAVE_FILE = 8; + public static final int REQUEST_EDIT_IMAGE = 9; + public static final int REQUEST_EXTENSION_COMPOSE = 10; + public static final int REQUEST_ADD_TAB = 11; + public static final int REQUEST_EDIT_TAB = 12; + public static final int REQUEST_PICK_FILE = 13; + public static final int REQUEST_PICK_DIRECTORY = 14; + public static final int REQUEST_ADD_TO_LIST = 15; + public static final int REQUEST_SELECT_USER = 16; + public static final int REQUEST_SELECT_USER_LIST = 17; + public static final int REQUEST_PICK_ACTIVITY = 18; + public static final int REQUEST_SETTINGS = 19; + public static final int REQUEST_OPEN_DOCUMENT = 20; + public static final int REQUEST_SWIPEBACK_ACTIVITY = 101; + + public static final int TABLE_ID_ACCOUNTS = 1; + public static final int TABLE_ID_STATUSES = 12; + public static final int TABLE_ID_MENTIONS = 13; + public static final int TABLE_ID_DIRECT_MESSAGES = 21; + public static final int TABLE_ID_DIRECT_MESSAGES_INBOX = 22; + public static final int TABLE_ID_DIRECT_MESSAGES_OUTBOX = 23; + public static final int TABLE_ID_DIRECT_MESSAGES_CONVERSATION = 24; + public static final int TABLE_ID_DIRECT_MESSAGES_CONVERSATION_SCREEN_NAME = 25; + public static final int TABLE_ID_DIRECT_MESSAGES_CONVERSATIONS_ENTRIES = 26; + public static final int TABLE_ID_FILTERED_USERS = 31; + public static final int TABLE_ID_FILTERED_KEYWORDS = 32; + public static final int TABLE_ID_FILTERED_SOURCES = 33; + public static final int TABLE_ID_FILTERED_LINKS = 34; + public static final int TABLE_ID_TRENDS_LOCAL = 41; + public static final int TABLE_ID_SAVED_SEARCHES = 42; + public static final int TABLE_ID_SEARCH_HISTORY = 43; + public static final int TABLE_ID_DRAFTS = 51; + public static final int TABLE_ID_TABS = 52; + public static final int TABLE_ID_CACHED_USERS = 61; + public static final int TABLE_ID_CACHED_STATUSES = 62; + public static final int TABLE_ID_CACHED_HASHTAGS = 63; + public static final int TABLE_ID_CACHED_RELATIONSHIPS = 64; + public static final int VIRTUAL_TABLE_ID_DATABASE_READY = 100; + public static final int VIRTUAL_TABLE_ID_NOTIFICATIONS = 101; + public static final int VIRTUAL_TABLE_ID_PREFERENCES = 102; + public static final int VIRTUAL_TABLE_ID_ALL_PREFERENCES = 103; + public static final int VIRTUAL_TABLE_ID_PERMISSIONS = 104; + public static final int VIRTUAL_TABLE_ID_DNS = 105; + public static final int VIRTUAL_TABLE_ID_CACHED_IMAGES = 106; + public static final int VIRTUAL_TABLE_ID_CACHE_FILES = 107; + public static final int VIRTUAL_TABLE_ID_UNREAD_COUNTS = 108; + public static final int VIRTUAL_TABLE_ID_UNREAD_COUNTS_BY_TYPE = 109; + public static final int VIRTUAL_TABLE_ID_CACHED_USERS_WITH_RELATIONSHIP = 121; + public static final int VIRTUAL_TABLE_ID_CACHED_USERS_WITH_SCORE = 122; + public static final int VIRTUAL_TABLE_ID_DRAFTS_UNSENT = 131; + + public static final int NOTIFICATION_ID_HOME_TIMELINE = 1; + public static final int NOTIFICATION_ID_MENTIONS_TIMELINE = 2; + public static final int NOTIFICATION_ID_DIRECT_MESSAGES = 3; + public static final int NOTIFICATION_ID_DRAFTS = 4; + public static final int NOTIFICATION_ID_DATA_PROFILING = 5; + public static final int NOTIFICATION_ID_UPDATE_STATUS = 101; + public static final int NOTIFICATION_ID_SEND_DIRECT_MESSAGE = 102; + + public static final String ICON_SPECIAL_TYPE_CUSTOMIZE = "_customize"; + + public static final String TASK_TAG_GET_HOME_TIMELINE = "get_home_tomeline"; + public static final String TASK_TAG_GET_MENTIONS = "get_mentions"; + public static final String TASK_TAG_GET_SENT_DIRECT_MESSAGES = "get_sent_direct_messages"; + public static final String TASK_TAG_GET_RECEIVED_DIRECT_MESSAGES = "get_received_direct_messages"; + public static final String TASK_TAG_GET_TRENDS = "get_trends"; + public static final String TASK_TAG_STORE_TRENDS = "store_trends"; + + public static final String SERVICE_COMMAND_REFRESH_ALL = "refresh_all"; + public static final String SERVICE_COMMAND_GET_HOME_TIMELINE = "get_home_timeline"; + public static final String SERVICE_COMMAND_GET_MENTIONS = "get_mentions"; + public static final String SERVICE_COMMAND_GET_SENT_DIRECT_MESSAGES = "get_sent_direct_messages"; + public static final String SERVICE_COMMAND_GET_RECEIVED_DIRECT_MESSAGES = "get_received_direct_messages"; + + public static final String METADATA_KEY_EXTENSION = "org.getlantern.firetweet.extension"; + public static final String METADATA_KEY_EXTENSION_PERMISSIONS = "org.getlantern.firetweet.extension.permissions"; + public static final String METADATA_KEY_EXTENSION_SETTINGS = "org.getlantern.firetweet.extension.settings"; + public static final String METADATA_KEY_EXTENSION_ICON = "org.getlantern.firetweet.extension.icon"; + public static final String METADATA_KEY_EXTENSION_USE_JSON = "org.getlantern.firetweet.extension.use_json"; + + public static final char SEPARATOR_PERMISSION = '|'; + public static final String SEPARATOR_PERMISSION_REGEX = "\\" + SEPARATOR_PERMISSION; + + public static final String PERMISSION_DENIED = "denied"; + public static final String PERMISSION_REFRESH = "refresh"; + public static final String PERMISSION_READ = "read"; + public static final String PERMISSION_WRITE = "write"; + public static final String PERMISSION_DIRECT_MESSAGES = "direct_messages"; + public static final String PERMISSION_ACCOUNTS = "accounts"; + public static final String PERMISSION_PREFERENCES = "preferences"; + + public static final String TAB_TYPE_HOME_TIMELINE = "home_timeline"; + public static final String TAB_TYPE_MENTIONS_TIMELINE = "mentions_timeline"; + public static final String TAB_TYPE_TRENDS_SUGGESTIONS = "trends_suggestions"; + public static final String TAB_TYPE_DIRECT_MESSAGES = "direct_messages"; + public static final String TAB_TYPE_FAVORITES = "favorites"; + public static final String TAB_TYPE_USER_TIMELINE = "user_timeline"; + public static final String TAB_TYPE_SEARCH_STATUSES = "search_statuses"; + public static final String TAB_TYPE_LIST_TIMELINE = "list_timeline"; + public static final String TAB_TYPE_ACTIVITIES_ABOUT_ME = "activities_about_me"; + public static final String TAB_TYPE_ACTIVITIES_BY_FRIENDS = "activities_by_friends"; + public static final String TAB_TYPE_RETWEETS_OF_ME = "retweets_of_me"; + + + public static final int TAB_CODE_HOME_TIMELINE = 1; + public static final int TAB_CODE_MENTIONS_TIMELINE = 2; + public static final int TAB_CODE_DIRECT_MESSAGES = 4; + + public static final int TWITTER_MAX_IMAGE_SIZE = 3145728; + public static final int TWITTER_MAX_IMAGE_WIDTH = 1024; + public static final int TWITTER_MAX_IMAGE_HEIGHT = 2048; + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/annotation/Preference.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/annotation/Preference.java new file mode 100644 index 00000000..f39df859 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/annotation/Preference.java @@ -0,0 +1,61 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Preference { + + boolean defaultBoolean() default false; + + float defaultFloat() default 0; + + int defaultInt() default 0; + + long defaultLong() default 0; + + int defaultResource() default 0; + + String defaultString() default ""; + + boolean exportable() default true; + + boolean hasDefault() default false; + + Type type() default Type.NULL; + + public static enum Type { + BOOLEAN(1), INT(2), LONG(3), FLOAT(4), STRING(5), NULL(0), INVALID(-1); + private int type; + + Type(final int type) { + this.type = type; + } + + public int getType() { + return type; + } + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/constant/IntentConstants.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/constant/IntentConstants.java new file mode 100644 index 00000000..7b6e2109 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/constant/IntentConstants.java @@ -0,0 +1,223 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.constant; + +public interface IntentConstants { + + public static final String INTENT_PACKAGE_PREFIX = "org.getlantern.firetweet."; + + public static final String INTENT_ACTION_HOME = INTENT_PACKAGE_PREFIX + "HOME"; + public static final String INTENT_ACTION_COMPOSE = INTENT_PACKAGE_PREFIX + "COMPOSE"; + public static final String INTENT_ACTION_REPLY = INTENT_PACKAGE_PREFIX + "REPLY"; + public static final String INTENT_ACTION_QUOTE = INTENT_PACKAGE_PREFIX + "QUOTE"; + public static final String INTENT_ACTION_EDIT_DRAFT = INTENT_PACKAGE_PREFIX + "EDIT_DRAFT"; + public static final String INTENT_ACTION_MENTION = INTENT_PACKAGE_PREFIX + "MENTION"; + public static final String INTENT_ACTION_REPLY_MULTIPLE = INTENT_PACKAGE_PREFIX + "REPLY_MULTIPLE"; + public static final String INTENT_ACTION_SETTINGS = INTENT_PACKAGE_PREFIX + "SETTINGS"; + public static final String INTENT_ACTION_SELECT_ACCOUNT = INTENT_PACKAGE_PREFIX + "SELECT_ACCOUNT"; + public static final String INTENT_ACTION_VIEW_MEDIA = INTENT_PACKAGE_PREFIX + "VIEW_MEDIA"; + public static final String INTENT_ACTION_FILTERS = INTENT_PACKAGE_PREFIX + "FILTERS"; + public static final String INTENT_ACTION_TWITTER_LOGIN = INTENT_PACKAGE_PREFIX + "TWITTER_LOGIN"; + public static final String INTENT_ACTION_DRAFTS = INTENT_PACKAGE_PREFIX + "DRAFTS"; + public static final String INTENT_ACTION_PICK_FILE = INTENT_PACKAGE_PREFIX + "PICK_FILE"; + public static final String INTENT_ACTION_PICK_DIRECTORY = INTENT_PACKAGE_PREFIX + "PICK_DIRECTORY"; + public static final String INTENT_ACTION_VIEW_WEBPAGE = INTENT_PACKAGE_PREFIX + "VIEW_WEBPAGE"; + public static final String INTENT_ACTION_EXTENSIONS = INTENT_PACKAGE_PREFIX + "EXTENSIONS"; + public static final String INTENT_ACTION_CUSTOM_TABS = INTENT_PACKAGE_PREFIX + "CUSTOM_TABS"; + public static final String INTENT_ACTION_ADD_TAB = INTENT_PACKAGE_PREFIX + "ADD_TAB"; + public static final String INTENT_ACTION_EDIT_TAB = INTENT_PACKAGE_PREFIX + "EDIT_TAB"; + public static final String INTENT_ACTION_EDIT_USER_PROFILE = INTENT_PACKAGE_PREFIX + "EDIT_USER_PROFILE"; + public static final String INTENT_ACTION_SERVICE_COMMAND = INTENT_PACKAGE_PREFIX + "SERVICE_COMMAND"; + public static final String INTENT_ACTION_REQUEST_PERMISSIONS = INTENT_PACKAGE_PREFIX + "REQUEST_PERMISSIONS"; + public static final String INTENT_ACTION_SELECT_USER_LIST = INTENT_PACKAGE_PREFIX + "SELECT_USER_LIST"; + public static final String INTENT_ACTION_SELECT_USER = INTENT_PACKAGE_PREFIX + "SELECT_USER"; + public static final String INTENT_ACTION_COMPOSE_TAKE_PHOTO = INTENT_PACKAGE_PREFIX + "COMPOSE_TAKE_PHOTO"; + public static final String INTENT_ACTION_COMPOSE_PICK_IMAGE = INTENT_PACKAGE_PREFIX + "COMPOSE_PICK_IMAGE"; + public static final String INTENT_ACTION_TAKE_PHOTO = INTENT_PACKAGE_PREFIX + "TAKE_PHOTO"; + public static final String INTENT_ACTION_PICK_IMAGE = INTENT_PACKAGE_PREFIX + "PICK_IMAGE"; + public static final String INTENT_ACTION_HIDDEN_SETTINGS_ENTRY = INTENT_PACKAGE_PREFIX + "HIDDEN_SETTINGS_ENTRY"; + + public static final String INTENT_ACTION_EXTENSION_EDIT_IMAGE = INTENT_PACKAGE_PREFIX + "EXTENSION_EDIT_IMAGE"; + public static final String INTENT_ACTION_EXTENSION_UPLOAD = INTENT_PACKAGE_PREFIX + "EXTENSION_UPLOAD"; + public static final String INTENT_ACTION_EXTENSION_OPEN_STATUS = INTENT_PACKAGE_PREFIX + "EXTENSION_OPEN_STATUS"; + public static final String INTENT_ACTION_EXTENSION_OPEN_USER = INTENT_PACKAGE_PREFIX + "EXTENSION_OPEN_USER"; + public static final String INTENT_ACTION_EXTENSION_OPEN_USER_LIST = INTENT_PACKAGE_PREFIX + + "EXTENSION_OPEN_USER_LIST"; + public static final String INTENT_ACTION_EXTENSION_COMPOSE = INTENT_PACKAGE_PREFIX + "EXTENSION_COMPOSE"; + public static final String INTENT_ACTION_EXTENSION_UPLOAD_MEDIA = INTENT_PACKAGE_PREFIX + "EXTENSION_UPLOAD_MEDIA"; + public static final String INTENT_ACTION_EXTENSION_SHORTEN_STATUS = INTENT_PACKAGE_PREFIX + + "EXTENSION_SHORTEN_STATUS"; + public static final String INTENT_ACTION_EXTENSION_SYNC_TIMELINE = INTENT_PACKAGE_PREFIX + + "EXTENSION_SYNC_TIMELINE"; + public static final String INTENT_ACTION_EXTENSION_SETTINGS = INTENT_PACKAGE_PREFIX + "EXTENSION_SETTINGS"; + + public static final String INTENT_ACTION_UPDATE_STATUS = INTENT_PACKAGE_PREFIX + "UPDATE_STATUS"; + public static final String INTENT_ACTION_SEND_DIRECT_MESSAGE = INTENT_PACKAGE_PREFIX + "SEND_DIRECT_MESSAGE"; + public static final String INTENT_ACTION_DISCARD_DRAFT = INTENT_PACKAGE_PREFIX + "DISCARD_DRAFT"; + public static final String INTENT_ACTION_PICK_ACTIVITY = "org.getlantern.firetweet.PICK_ACTIVITY"; + + public static final String INTENT_ACTION_PEBBLE_NOTIFICATION = "com.getpebble.action.SEND_NOTIFICATION"; + + public static final String BROADCAST_NOTIFICATION_DELETED = INTENT_PACKAGE_PREFIX + "NOTIFICATION_DELETED"; + public static final String BROADCAST_USER_LIST_DETAILS_UPDATED = INTENT_PACKAGE_PREFIX + + "USER_LIST_DETAILS_UPDATED"; + public static final String BROADCAST_FRIENDSHIP_ACCEPTED = INTENT_PACKAGE_PREFIX + "FRIENDSHIP_ACCEPTED"; + public static final String BROADCAST_FRIENDSHIP_DENIED = INTENT_PACKAGE_PREFIX + "FRIENDSHIP_DENIED"; + + public static final String BROADCAST_USER_LIST_MEMBERS_DELETED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_DELETED"; + public static final String BROADCAST_USER_LIST_MEMBERS_ADDED = INTENT_PACKAGE_PREFIX + "USER_LIST_MEMBER_ADDED"; + public static final String BROADCAST_USER_LIST_SUBSCRIBED = INTENT_PACKAGE_PREFIX + "USER_LIST_SUBSRCIBED"; + public static final String BROADCAST_USER_LIST_UNSUBSCRIBED = INTENT_PACKAGE_PREFIX + "USER_LIST_UNSUBSCRIBED"; + public static final String BROADCAST_USER_LIST_CREATED = INTENT_PACKAGE_PREFIX + "USER_LIST_CREATED"; + public static final String BROADCAST_USER_LIST_DELETED = INTENT_PACKAGE_PREFIX + "USER_LIST_DELETED"; + public static final String BROADCAST_FILTERS_UPDATED = INTENT_PACKAGE_PREFIX + "FILTERS_UPDATED"; + public static final String BROADCAST_REFRESH_HOME_TIMELINE = INTENT_PACKAGE_PREFIX + "REFRESH_HOME_TIMELINE"; + public static final String BROADCAST_REFRESH_MENTIONS = INTENT_PACKAGE_PREFIX + "REFRESH_MENTIONS"; + public static final String BROADCAST_REFRESH_DIRECT_MESSAGES = INTENT_PACKAGE_PREFIX + "REFRESH_DIRECT_MESSAGES"; + public static final String BROADCAST_REFRESH_TRENDS = INTENT_PACKAGE_PREFIX + "REFRESH_TRENDS"; + public static final String BROADCAST_RESCHEDULE_HOME_TIMELINE_REFRESHING = INTENT_PACKAGE_PREFIX + + "RESCHEDULE_HOME_TIMELINE_REFRESHING"; + public static final String BROADCAST_RESCHEDULE_MENTIONS_REFRESHING = INTENT_PACKAGE_PREFIX + + "RESCHEDULE_MENTIONS_REFRESHING"; + public static final String BROADCAST_RESCHEDULE_DIRECT_MESSAGES_REFRESHING = INTENT_PACKAGE_PREFIX + + "RESCHEDULE_DIRECT_MESSAGES_REFRESHING"; + public static final String BROADCAST_RESCHEDULE_TRENDS_REFRESHING = INTENT_PACKAGE_PREFIX + + "RESCHEDULE_TRENDS_REFRESHING"; + public static final String BROADCAST_MULTI_BLOCKSTATE_CHANGED = INTENT_PACKAGE_PREFIX + "MULTI_BLOCKSTATE_CHANGED"; + public static final String BROADCAST_MULTI_MUTESTATE_CHANGED = INTENT_PACKAGE_PREFIX + "MULTI_MUTESTATE_CHANGED"; + public static final String BROADCAST_HOME_ACTIVITY_ONCREATE = INTENT_PACKAGE_PREFIX + "HOME_ACTIVITY_ONCREATE"; + public static final String BROADCAST_HOME_ACTIVITY_ONSTART = INTENT_PACKAGE_PREFIX + "HOME_ACTIVITY_ONSTART"; + public static final String BROADCAST_HOME_ACTIVITY_ONRESUME = INTENT_PACKAGE_PREFIX + "HOME_ACTIVITY_ONRESUME"; + public static final String BROADCAST_HOME_ACTIVITY_ONPAUSE = INTENT_PACKAGE_PREFIX + "HOME_ACTIVITY_ONPAUSE"; + public static final String BROADCAST_HOME_ACTIVITY_ONSTOP = INTENT_PACKAGE_PREFIX + "HOME_ACTIVITY_ONSTOP"; + public static final String BROADCAST_HOME_ACTIVITY_ONDESTROY = INTENT_PACKAGE_PREFIX + "HOME_ACTIVITY_ONDESTROY"; + public static final String BROADCAST_DATABASE_READY = INTENT_PACKAGE_PREFIX + "DATABASE_READY"; + + public static final String EXTRA_LATITUDE = "latitude"; + public static final String EXTRA_LONGITUDE = "longitude"; + public static final String EXTRA_URI = "uri"; + public static final String EXTRA_URI_ORIG = "uri_orig"; + public static final String EXTRA_MENTIONS = "mentions"; + public static final String EXTRA_ACCOUNT_ID = "account_id"; + public static final String EXTRA_ACCOUNT_IDS = "account_ids"; + public static final String EXTRA_PAGE = "page"; + public static final String EXTRA_DATA = "data"; + public static final String EXTRA_QUERY = "query"; + public static final String EXTRA_QUERY_TYPE = "query_type"; + public static final String EXTRA_USER_ID = "user_id"; + public static final String EXTRA_USER_IDS = "user_ids"; + public static final String EXTRA_LIST_ID = "list_id"; + public static final String EXTRA_MAX_ID = "max_id"; + public static final String EXTRA_MAX_IDS = "max_ids"; + public static final String EXTRA_SINCE_ID = "since_id"; + public static final String EXTRA_SINCE_IDS = "since_ids"; + public static final String EXTRA_STATUS_ID = "status_id"; + public static final String EXTRA_SCREEN_NAME = "screen_name"; + public static final String EXTRA_SCREEN_NAMES = "screen_names"; + public static final String EXTRA_LIST_NAME = "list_name"; + public static final String EXTRA_DESCRIPTION = "description"; + public static final String EXTRA_IN_REPLY_TO_ID = "in_reply_to_id"; + public static final String EXTRA_IN_REPLY_TO_NAME = "in_reply_to_name"; + public static final String EXTRA_IN_REPLY_TO_SCREEN_NAME = "in_reply_to_screen_name"; + public static final String EXTRA_TEXT = "text"; + public static final String EXTRA_TITLE = "title"; + public static final String EXTRA_TYPE = "type"; + // public static final String EXTRA_SUCCEED = "succeed"; + public static final String EXTRA_IDS = "ids"; + public static final String EXTRA_REFRESH_IDS = "refresh_ids"; + public static final String EXTRA_IS_SHARE = "is_share"; + public static final String EXTRA_STATUS = "status"; + public static final String EXTRA_MESSAGE = "message"; + public static final String EXTRA_STATUS_JSON = "status_json"; + public static final String EXTRA_STATUSES = "statuses"; + public static final String EXTRA_DRAFT = "draft"; + public static final String EXTRA_FAVORITED = "favorited"; + public static final String EXTRA_RETWEETED = "retweeted"; + public static final String EXTRA_FILENAME = "filename"; + public static final String EXTRA_FILE_SOURCE = "file_source"; + public static final String EXTRA_FILE_EXTENSIONS = "file_extensions"; + public static final String EXTRA_ITEMS_INSERTED = "items_inserted"; + public static final String EXTRA_INITIAL_TAB = "initial_tab"; + public static final String EXTRA_NOTIFICATION_ID = "notification_id"; + public static final String EXTRA_NOTIFICATION_ACCOUNT = "notification_account"; + public static final String EXTRA_FROM_NOTIFICATION = "from_notification"; + public static final String EXTRA_IS_PUBLIC = "is_public"; + public static final String EXTRA_USER = "user"; + public static final String EXTRA_USERS = "users"; + public static final String EXTRA_USER_LIST = "user_list"; + public static final String EXTRA_APPEND_TEXT = "append_text"; + public static final String EXTRA_NAME = "name"; + public static final String EXTRA_TEXT1 = "text1"; + public static final String EXTRA_TEXT2 = "text2"; + public static final String EXTRA_POSITION = "position"; + public static final String EXTRA_ARGUMENTS = "arguments"; + public static final String EXTRA_ICON = "icon"; + public static final String EXTRA_ID = "id"; + public static final String EXTRA_RESID = "resid"; + public static final String EXTRA_SETTINGS_INTENT_ACTION = "settings_intent_action"; + public static final String EXTRA_IMAGE_URI = "image_uri"; + public static final String EXTRA_ATTACHED_IMAGE_TYPE = "attached_image_type"; + public static final String EXTRA_ACTIVATED_ONLY = "activated_only"; + public static final String EXTRA_TAB_POSITION = "tab_position"; + public static final String EXTRA_HAS_RUNNING_TASK = "has_running_task"; + public static final String EXTRA_OAUTH_VERIFIER = "oauth_verifier"; + public static final String EXTRA_REQUEST_TOKEN = "request_token"; + public static final String EXTRA_REQUEST_TOKEN_SECRET = "request_token_secret"; + public static final String EXTRA_OMIT_INTENT_EXTRA = "omit_intent_extra"; + public static final String EXTRA_COMMAND = "command"; + public static final String EXTRA_WIDTH = "width"; + public static final String EXTRA_ALLOW_SELECT_NONE = "allow_select_none"; + public static final String EXTRA_SINGLE_SELECTION = "single_selection"; + public static final String EXTRA_OAUTH_ONLY = "oauth_only"; + public static final String EXTRA_PERMISSIONS = "permissions"; + public static final String EXTRA_LOCATION = "location"; + public static final String EXTRA_URL = "url"; + public static final String EXTRA_NEXT_CURSOR = "next_cursor"; + public static final String EXTRA_PREV_CURSOR = "prev_cursor"; + public static final String EXTRA_EXTRA_INTENT = "extra_intent"; + public static final String EXTRA_IS_MY_ACCOUNT = "is_my_account"; + public static final String EXTRA_TAB_TYPE = "tab_type"; + public static final String EXTRA_ACCOUNT = "account"; + public static final String EXTRA_ACTIVITY_SCREENSHOT_ID = "activity_screenshot_id"; + public static final String EXTRA_COLOR = "color"; + public static final String EXTRA_ALPHA_SLIDER = "alpha_slider"; + public static final String EXTRA_OPEN_ACCOUNTS_DRAWER = "open_accounts_drawer"; + public static final String EXTRA_RECIPIENT_ID = "recipient_id"; + public static final String EXTRA_OFFICIAL_KEY_ONLY = "official_key_only"; + public static final String EXTRA_SEARCH_ID = "search_id"; + public static final String EXTRA_CLEAR_BUTTON = "clear_button"; + public static final String EXTRA_PATH = "path"; + public static final String EXTRA_ACTION = "action"; + public static final String EXTRA_FLAGS = "flags"; + public static final String EXTRA_INTENT = "intent"; + public static final String EXTRA_BLACKLIST = "blacklist"; + public static final String EXTRA_MEDIA = "media"; + public static final String EXTRA_CURRENT_MEDIA = "current_media"; + public static final String EXTRA_EXTRAS = "extras"; + public static final String EXTRA_MY_FOLLOWING_ONLY = "my_following_only"; + public static final String EXTRA_RESTART_ACTIVITY = "restart_activity"; + public static final String EXTRA_FROM_USER = "from_user"; + public static final String EXTRA_SHOW_MEDIA_PREVIEW = "show_media_preview"; + public static final String EXTRA_SHOW_EXTRA_TYPE = "show_extra_type"; + public static final String EXTRA_BITMAP = "bitmap"; + public static final String EXTRA_SOURCE = "source"; + public static final String EXTRA_DESTINATION = "destination"; + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/constant/SharedPreferenceConstants.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/constant/SharedPreferenceConstants.java new file mode 100644 index 00000000..a4363e86 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/constant/SharedPreferenceConstants.java @@ -0,0 +1,311 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.constant; + +import org.getlantern.firetweet.TwidereConstants; +import org.getlantern.firetweet.annotation.Preference; +import org.getlantern.firetweet.provider.TwidereDataStore.Accounts; + +import static org.getlantern.firetweet.annotation.Preference.Type.BOOLEAN; +import static org.getlantern.firetweet.annotation.Preference.Type.INT; +import static org.getlantern.firetweet.annotation.Preference.Type.LONG; +import static org.getlantern.firetweet.annotation.Preference.Type.STRING; + +public interface SharedPreferenceConstants { + + String FORMAT_PATTERN_TITLE = "[TITLE]"; + String FORMAT_PATTERN_TEXT = "[TEXT]"; + String FORMAT_PATTERN_NAME = "[NAME]"; + String FORMAT_PATTERN_LINK = "[LINK]"; + + String VALUE_NONE = "none"; + String VALUE_LINK_HIGHLIGHT_OPTION_NONE = VALUE_NONE; + String VALUE_LINK_HIGHLIGHT_OPTION_HIGHLIGHT = "highlight"; + String VALUE_LINK_HIGHLIGHT_OPTION_UNDERLINE = "underline"; + String VALUE_LINK_HIGHLIGHT_OPTION_BOTH = "both"; + int VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE = 0x0; + int VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT = 0x1; + int VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE = 0x2; + int VALUE_LINK_HIGHLIGHT_OPTION_CODE_BOTH = VALUE_LINK_HIGHLIGHT_OPTION_CODE_HIGHLIGHT + | VALUE_LINK_HIGHLIGHT_OPTION_CODE_UNDERLINE; + + String VALUE_MEDIA_PREVIEW_STYLE_CROP = "crop"; + String VALUE_MEDIA_PREVIEW_STYLE_SCALE = "scale"; + String VALUE_MEDIA_PREVIEW_STYLE_NONE = VALUE_NONE; + + int VALUE_MEDIA_PREVIEW_STYLE_CODE_CROP = 1; + int VALUE_MEDIA_PREVIEW_STYLE_CODE_SCALE = 2; + int VALUE_MEDIA_PREVIEW_STYLE_CODE_NONE = 0; + + String VALUE_THEME_FONT_FAMILY_REGULAR = "sans-serif"; + String VALUE_THEME_FONT_FAMILY_CONDENSED = "sans-serif-condensed"; + String VALUE_THEME_FONT_FAMILY_LIGHT = "sans-serif-light"; + String VALUE_THEME_FONT_FAMILY_THIN = "sans-serif-thin"; + + int VALUE_NOTIFICATION_FLAG_NONE = 0x0; + int VALUE_NOTIFICATION_FLAG_RINGTONE = 0x1; + int VALUE_NOTIFICATION_FLAG_VIBRATION = 0x2; + int VALUE_NOTIFICATION_FLAG_LIGHT = 0x4; + + String VALUE_COMPOSE_QUIT_ACTION_ASK = "ask"; + String VALUE_COMPOSE_QUIT_ACTION_SAVE = "save"; + String VALUE_COMPOSE_QUIT_ACTION_DISCARD = "discard"; + + String VALUE_TAB_DIPLAY_OPTION_ICON = "icon"; + String VALUE_TAB_DIPLAY_OPTION_LABEL = "label"; + String VALUE_TAB_DIPLAY_OPTION_BOTH = "both"; + int VALUE_TAB_DIPLAY_OPTION_CODE_ICON = 0x1; + int VALUE_TAB_DIPLAY_OPTION_CODE_LABEL = 0x2; + int VALUE_TAB_DIPLAY_OPTION_CODE_BOTH = VALUE_TAB_DIPLAY_OPTION_CODE_ICON + | VALUE_TAB_DIPLAY_OPTION_CODE_LABEL; + + String VALUE_THEME_BACKGROUND_DEFAULT = "default"; + String VALUE_THEME_BACKGROUND_SOLID = "solid"; + String VALUE_THEME_BACKGROUND_TRANSPARENT = "transparent"; + + String VALUE_THEME_NAME_TWIDERE = "twidere"; + String VALUE_THEME_NAME_DARK = "dark"; + String VALUE_THEME_NAME_LIGHT = "light"; + + String VALUE_PROFILE_IMAGE_STYLE_ROUND = "round"; + String VALUE_PROFILE_IMAGE_STYLE_SQUARE = "square"; + + String VALUE_COMPOSE_NOW_ACTION_COMPOSE = "compose"; + String VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO = "take_photo"; + String VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE = "pick_image"; + + String VALUE_CARD_HIGHLIGHT_OPTION_NONE = VALUE_NONE; + String VALUE_CARD_HIGHLIGHT_OPTION_BACKGROUND = "background"; + String VALUE_CARD_HIGHLIGHT_OPTION_LINE = "line"; + + int VALUE_CARD_HIGHLIGHT_OPTION_CODE_NONE = 0x0; + int VALUE_CARD_HIGHLIGHT_OPTION_CODE_BACKGROUND = 0x1; + int VALUE_CARD_HIGHLIGHT_OPTION_CODE_LINE = 0x2; + + String DEFAULT_THEME = VALUE_THEME_NAME_TWIDERE; + String DEFAULT_THEME_BACKGROUND = VALUE_THEME_BACKGROUND_DEFAULT; + String DEFAULT_THEME_FONT_FAMILY = VALUE_THEME_FONT_FAMILY_REGULAR; + int DEFAULT_THEME_BACKGROUND_ALPHA = 160; + + String DEFAULT_QUOTE_FORMAT = "RT @" + FORMAT_PATTERN_NAME + ": " + FORMAT_PATTERN_TEXT; + String DEFAULT_SHARE_FORMAT = FORMAT_PATTERN_TITLE + " - " + FORMAT_PATTERN_TEXT; + String DEFAULT_IMAGE_UPLOAD_FORMAT = FORMAT_PATTERN_TEXT + " " + FORMAT_PATTERN_LINK; + + String DEFAULT_REFRESH_INTERVAL = "15"; + boolean DEFAULT_AUTO_REFRESH = true; + boolean DEFAULT_AUTO_REFRESH_HOME_TIMELINE = false; + boolean DEFAULT_AUTO_REFRESH_MENTIONS = true; + boolean DEFAULT_AUTO_REFRESH_DIRECT_MESSAGES = true; + boolean DEFAULT_AUTO_REFRESH_TRENDS = false; + boolean DEFAULT_NOTIFICATION = true; + int DEFAULT_NOTIFICATION_TYPE_HOME = VALUE_NOTIFICATION_FLAG_NONE; + int DEFAULT_NOTIFICATION_TYPE_MENTIONS = VALUE_NOTIFICATION_FLAG_VIBRATION + | VALUE_NOTIFICATION_FLAG_LIGHT; + int DEFAULT_NOTIFICATION_TYPE_DIRECT_MESSAGES = VALUE_NOTIFICATION_FLAG_RINGTONE + | VALUE_NOTIFICATION_FLAG_VIBRATION | VALUE_NOTIFICATION_FLAG_LIGHT; + + boolean DEFAULT_HOME_TIMELINE_NOTIFICATION = false; + boolean DEFAULT_MENTIONS_NOTIFICATION = true; + boolean DEFAULT_DIRECT_MESSAGES_NOTIFICATION = true; + + int DEFAULT_DATABASE_ITEM_LIMIT = 100; + int DEFAULT_LOAD_ITEM_LIMIT = 20; + String DEFAULT_CARD_HIGHLIGHT_OPTION = VALUE_CARD_HIGHLIGHT_OPTION_BACKGROUND; + + @Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_DATABASE_ITEM_LIMIT) + String KEY_DATABASE_ITEM_LIMIT = "database_item_limit"; + @Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_LOAD_ITEM_LIMIT) + String KEY_LOAD_ITEM_LIMIT = "load_item_limit"; + @Preference(type = INT, hasDefault = true, defaultInt = 15) + String KEY_TEXT_SIZE = "text_size_int"; + @Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME) + String KEY_THEME = "theme"; + @Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME_BACKGROUND) + String KEY_THEME_BACKGROUND = "theme_background"; + @Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_THEME_BACKGROUND_ALPHA) + String KEY_THEME_BACKGROUND_ALPHA = "theme_background_alpha"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_THEME_DARK_ACTIONBAR = "theme_dark_actionbar"; + @Preference(type = INT) + String KEY_THEME_COLOR = "theme_color"; + @Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME_FONT_FAMILY) + String KEY_THEME_FONT_FAMILY = "theme_font_family"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_DISPLAY_PROFILE_IMAGE = "display_profile_image"; + @Preference(type = BOOLEAN) + String KEY_LEFTSIDE_COMPOSE_BUTTON = "leftside_compose_button"; + @Preference(type = BOOLEAN) + String KEY_ATTACH_LOCATION = "attach_location"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_GZIP_COMPRESSING = "gzip_compressing"; + @Preference(type = BOOLEAN) + String KEY_IGNORE_SSL_ERROR = "ignore_ssl_error"; + @Preference(type = BOOLEAN) + String KEY_LOAD_MORE_AUTOMATICALLY = "load_more_automatically"; + @Preference(type = STRING) + String KEY_QUOTE_FORMAT = "quote_format"; + @Preference(type = BOOLEAN) + String KEY_REMEMBER_POSITION = "remember_position"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_READ_FROM_BOTTOM = "read_from_bottom"; + @Preference(type = INT, exportable = false) + String KEY_SAVED_TAB_POSITION = "saved_tab_position"; + @Preference(type = BOOLEAN) + String KEY_ENABLE_PROXY = "enable_proxy"; + @Preference(type = STRING) + String KEY_PROXY_HOST = "proxy_host"; + @Preference(type = STRING) + String KEY_PROXY_PORT = "proxy_port"; + @Preference(type = BOOLEAN) + String KEY_REFRESH_ON_START = "refresh_on_start"; + @Preference(type = BOOLEAN) + String KEY_REFRESH_AFTER_TWEET = "refresh_after_tweet"; + @Preference(type = BOOLEAN) + String KEY_AUTO_REFRESH = "auto_refresh"; + @Preference(type = STRING) + String KEY_REFRESH_INTERVAL = "refresh_interval"; + @Preference(type = BOOLEAN) + String KEY_AUTO_REFRESH_HOME_TIMELINE = "auto_refresh_home_timeline"; + @Preference(type = BOOLEAN) + String KEY_AUTO_REFRESH_MENTIONS = "auto_refresh_mentions"; + @Preference(type = BOOLEAN) + String KEY_AUTO_REFRESH_DIRECT_MESSAGES = "auto_refresh_direct_messages"; + @Preference(type = BOOLEAN) + String KEY_AUTO_REFRESH_TRENDS = "auto_refresh_trends"; + @Preference(type = BOOLEAN) + String KEY_HOME_TIMELINE_NOTIFICATION = "home_timeline_notification"; + @Preference(type = BOOLEAN) + String KEY_MENTIONS_NOTIFICATION = "mentions_notification"; + @Preference(type = BOOLEAN) + String KEY_DIRECT_MESSAGES_NOTIFICATION = "direct_messages_notification"; + @Preference(type = INT) + String KEY_LOCAL_TRENDS_WOEID = "local_trends_woeid"; + String KEY_NOTIFICATION_RINGTONE = "notification_ringtone"; + String KEY_NOTIFICATION_LIGHT_COLOR = "notification_light_color"; + String KEY_SHARE_FORMAT = "share_format"; + String KEY_HOME_REFRESH_MENTIONS = "home_refresh_mentions"; + String KEY_HOME_REFRESH_DIRECT_MESSAGES = "home_refresh_direct_messages"; + String KEY_HOME_REFRESH_TRENDS = "home_refresh_trends"; + String KEY_IMAGE_UPLOAD_FORMAT = "image_upload_format"; + String KEY_STATUS_SHORTENER = "status_shortener"; + String KEY_MEDIA_UPLOADER = "media_uploader"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_SHOW_ABSOLUTE_TIME = "show_absolute_time"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_QUICK_SEND = "quick_send"; + @Preference(type = STRING, exportable = false) + String KEY_COMPOSE_ACCOUNTS = "compose_accounts"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_TCP_DNS_QUERY = "tcp_dns_query"; + @Preference(type = STRING, hasDefault = true, defaultString = "8.8.8.8") + String KEY_DNS_SERVER = "dns_server"; + String KEY_CONNECTION_TIMEOUT = "connection_timeout"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_NAME_FIRST = "name_first"; + String KEY_STOP_AUTO_REFRESH_WHEN_BATTERY_LOW = "stop_auto_refresh_when_battery_low"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_DISPLAY_SENSITIVE_CONTENTS = "display_sensitive_contents"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_PHISHING_LINK_WARNING = "phishing_link_warning"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_FAST_SCROLL_THUMB = "fast_scroll_thumb"; + String KEY_LINK_HIGHLIGHT_OPTION = "link_highlight_option"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_INDICATE_MY_STATUS = "indicate_my_status"; + String KEY_PRELOAD_PROFILE_IMAGES = "preload_profile_images"; + String KEY_PRELOAD_PREVIEW_IMAGES = "preload_preview_images"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_PRELOAD_WIFI_ONLY = "preload_wifi_only"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_LINK_TO_QUOTED_TWEET = "link_to_quoted_tweet"; + @Preference(type = BOOLEAN) + String KEY_BACKGROUND_TOAST_NOTIFICATION = "background_toast_notification"; + @Preference(type = STRING) + String KEY_COMPOSE_QUIT_ACTION = "compose_quit_action"; + @Preference(type = BOOLEAN) + String KEY_NO_CLOSE_AFTER_TWEET_SENT = "no_close_after_tweet_sent"; + @Preference(type = BOOLEAN) + String KEY_FAST_IMAGE_LOADING = "fast_image_loading"; + @Preference(type = STRING, hasDefault = false) + String KEY_API_URL_FORMAT = "api_url_format"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_SAME_OAUTH_SIGNING_URL = "same_oauth_signing_url"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_NO_VERSION_SUFFIX = "no_version_suffix"; + @Preference(type = INT, hasDefault = true, defaultInt = Accounts.AUTH_TYPE_OAUTH) + String KEY_AUTH_TYPE = "auth_type"; + @Preference(type = STRING, hasDefault = true, defaultString = TwidereConstants.TWITTER_CONSUMER_KEY_3) + String KEY_CONSUMER_KEY = "consumer_key"; + @Preference(type = STRING, hasDefault = true, defaultString = TwidereConstants.TWITTER_CONSUMER_SECRET_3) + String KEY_CONSUMER_SECRET = "consumer_secret"; + String KEY_SETTINGS_WIZARD_COMPLETED = "settings_wizard_completed"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true) + String KEY_CARD_ANIMATION = "card_animation"; + String KEY_UNREAD_COUNT = "unread_count"; + String KEY_NOTIFICATION = "notification"; + String KEY_NOTIFICATION_TYPE_HOME = "notification_type_home"; + String KEY_NOTIFICATION_TYPE_MENTIONS = "notification_type_mentions"; + String KEY_NOTIFICATION_TYPE_DIRECT_MESSAGES = "notification_type_direct_messages"; + String KEY_NOTIFICATION_FOLLOWING_ONLY = "notification_following_only"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_PEBBLE_NOTIFICATIONS = "pebble_notifications"; + + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_COMPACT_CARDS = "compact_cards"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_FORCE_USING_PRIVATE_APIS = "force_using_private_apis"; + @Preference(type = STRING, hasDefault = true, defaultString = "140") + String KEY_STATUS_TEXT_LIMIT = "status_text_limit"; + @Preference(type = STRING, hasDefault = true, defaultString = VALUE_COMPOSE_NOW_ACTION_COMPOSE) + String KEY_COMPOSE_NOW_ACTION = "compose_now_action"; + String KEY_FALLBACK_TWITTER_LINK_HANDLER = "fallback_twitter_link_handler"; + + @Preference(type = STRING, hasDefault = true, defaultString = VALUE_MEDIA_PREVIEW_STYLE_CROP) + String KEY_MEDIA_PREVIEW_STYLE = "media_preview_style"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_MEDIA_PREVIEW = "media_preview"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_SORT_TIMELINE_BY_ID = "sort_timeline_by_id"; + @Preference(type = STRING, hasDefault = true) + String KEY_PROFILE_IMAGE_STYLE = "profile_image_style"; + + String KEY_QUICK_MENU_EXPANDED = "quick_menu_expanded"; + + @Preference(type = STRING) + String KEY_TRANSLATION_DESTINATION = "translation_destination"; + @Preference(type = STRING) + String KEY_TAB_DISPLAY_OPTION = "tab_display_option"; + @Preference(type = STRING) + String KEY_CARD_HIGHLIGHT_OPTION = "card_highlight_option"; + @Preference(type = INT, exportable = false) + String KEY_LIVE_WALLPAPER_SCALE = "live_wallpaper_scale"; + @Preference(type = LONG, exportable = false) + String KEY_API_LAST_CHANGE = "api_last_change"; + @Preference(type = LONG, exportable = false) + String KEY_DEFAULT_ACCOUNT_ID = "default_account_id"; + + + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_THUMBOR_ENABLED = "thumbor_enabled"; + String KEY_THUMBOR_ADDRESS = "thumbor_address"; + String KEY_THUMBOR_SECURITY_KEY = "thumbor_security_key"; + @Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false) + String KEY_HIDE_CARD_ACTIONS = "hide_card_actions"; +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/DraftItem.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/DraftItem.java new file mode 100644 index 00000000..9ffbbafe --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/DraftItem.java @@ -0,0 +1,143 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import org.json.JSONException; +import org.json.JSONObject; +import org.getlantern.firetweet.provider.TwidereDataStore.Drafts; +import org.getlantern.firetweet.util.TwidereArrayUtils; + +public class DraftItem implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public DraftItem createFromParcel(final Parcel in) { + return new DraftItem(in); + } + + @Override + public DraftItem[] newArray(final int size) { + return new DraftItem[size]; + } + }; + + public final long[] account_ids; + public final long _id, in_reply_to_status_id, timestamp; + public final String text; + public final ParcelableMediaUpdate[] media; + public final boolean is_possibly_sensitive; + public final ParcelableLocation location; + public final int action_type; + public final JSONObject action_extras; + + public DraftItem(final Cursor cursor, final CursorIndices indices) { + _id = cursor.getLong(indices._id); + text = cursor.getString(indices.text); + media = ParcelableMediaUpdate.fromJSONString(cursor.getString(indices.media)); + account_ids = TwidereArrayUtils.parseLongArray(cursor.getString(indices.account_ids), ','); + in_reply_to_status_id = cursor.getLong(indices.in_reply_to_status_id); + is_possibly_sensitive = cursor.getShort(indices.is_possibly_sensitive) == 1; + location = new ParcelableLocation(cursor.getString(indices.location)); + timestamp = cursor.getLong(indices.timestamp); + action_type = cursor.getInt(indices.action_type); + action_extras = createJSONObject(cursor.getString(indices.action_extras)); + } + + public DraftItem(final Parcel in) { + account_ids = in.createLongArray(); + _id = in.readLong(); + in_reply_to_status_id = in.readLong(); + text = in.readString(); + media = in.createTypedArray(ParcelableMediaUpdate.CREATOR); + is_possibly_sensitive = in.readInt() == 1; + location = ParcelableLocation.fromString(in.readString()); + timestamp = in.readLong(); + action_type = in.readInt(); + action_extras = createJSONObject(in.readString()); + } + + public DraftItem(final ParcelableStatusUpdate status) { + _id = 0; + account_ids = ParcelableAccount.getAccountIds(status.accounts); + in_reply_to_status_id = status.in_reply_to_status_id; + text = status.text; + media = status.media; + is_possibly_sensitive = status.is_possibly_sensitive; + location = status.location; + timestamp = System.currentTimeMillis(); + action_type = Drafts.ACTION_UPDATE_STATUS; + action_extras = createJSONObject(null); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeLongArray(account_ids); + out.writeLong(_id); + out.writeLong(in_reply_to_status_id); + out.writeString(text); + out.writeTypedArray(media, flags); + out.writeInt(is_possibly_sensitive ? 1 : 0); + out.writeString(ParcelableLocation.toString(location)); + out.writeLong(timestamp); + out.writeInt(action_type); + out.writeString(action_extras.toString()); + } + + private static JSONObject createJSONObject(final String json) { + if (TextUtils.isEmpty(json)) return new JSONObject(); + try { + return new JSONObject(json); + } catch (final JSONException e) { + e.printStackTrace(); + } + return new JSONObject(); + } + + public static final class CursorIndices { + + public final int _id, account_ids, in_reply_to_status_id, text, location, media, is_possibly_sensitive, + timestamp, action_type, action_extras; + + public CursorIndices(final Cursor cursor) { + _id = cursor.getColumnIndex(Drafts._ID); + account_ids = cursor.getColumnIndex(Drafts.ACCOUNT_IDS); + in_reply_to_status_id = cursor.getColumnIndex(Drafts.IN_REPLY_TO_STATUS_ID); + timestamp = cursor.getColumnIndex(Drafts.TIMESTAMP); + text = cursor.getColumnIndex(Drafts.TEXT); + media = cursor.getColumnIndex(Drafts.MEDIA); + is_possibly_sensitive = cursor.getColumnIndex(Drafts.IS_POSSIBLY_SENSITIVE); + location = cursor.getColumnIndex(Drafts.LOCATION); + action_type = cursor.getColumnIndex(Drafts.ACTION_TYPE); + action_extras = cursor.getColumnIndex(Drafts.ACTION_EXTRAS); + } + + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/MediaUploadResult.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/MediaUploadResult.java new file mode 100644 index 00000000..040fca53 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/MediaUploadResult.java @@ -0,0 +1,73 @@ +package org.getlantern.firetweet.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; + +public class MediaUploadResult implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + + @Override + public MediaUploadResult createFromParcel(final Parcel source) { + return new MediaUploadResult(source); + } + + @Override + public MediaUploadResult[] newArray(final int size) { + return new MediaUploadResult[size]; + } + }; + + public final String[] media_uris; + public final int error_code; + public final String error_message; + + public MediaUploadResult(final int errorCode, final String errorMessage) { + if (errorCode == 0) throw new IllegalArgumentException("Error code must not be 0"); + media_uris = null; + error_code = errorCode; + error_message = errorMessage; + } + + public MediaUploadResult(final Parcel src) { + media_uris = src.createStringArray(); + error_code = src.readInt(); + error_message = src.readString(); + } + + public MediaUploadResult(final String[] mediaUris) { + if (mediaUris == null) throw new IllegalArgumentException("Media uris must not be null"); + media_uris = mediaUris; + error_code = 0; + error_message = null; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "MediaUploadResult{media_uris=" + Arrays.toString(media_uris) + ", error_code=" + error_code + + ", error_message=" + error_message + "}"; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeStringArray(media_uris); + dest.writeInt(error_code); + dest.writeString(error_message); + } + + public static MediaUploadResult getInstance(final int errorCode, final String errorMessage) { + return new MediaUploadResult(errorCode, errorMessage); + } + + public static MediaUploadResult getInstance(final String... mediaUris) { + return new MediaUploadResult(mediaUris); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableAccount.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableAccount.java new file mode 100644 index 00000000..c6f9a9e0 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableAccount.java @@ -0,0 +1,380 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.content.Context; +import android.database.Cursor; +import android.graphics.Color; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.getlantern.querybuilder.Columns.Column; +import org.getlantern.querybuilder.Expression; +import org.getlantern.querybuilder.RawItemArray; +import org.getlantern.firetweet.provider.TwidereDataStore.Accounts; +import org.getlantern.firetweet.util.TwitterContentUtils; +import org.getlantern.firetweet.util.content.ContentResolverUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ParcelableAccount implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + + @Override + public ParcelableAccount createFromParcel(final Parcel in) { + return new ParcelableAccount(in); + } + + @Override + public ParcelableAccount[] newArray(final int size) { + return new ParcelableAccount[size]; + } + }; + + public final String screen_name, name, profile_image_url, profile_banner_url; + public final long account_id; + public final int color; + public final boolean is_activated; + public final boolean is_dummy; + + public ParcelableAccount(final Cursor cursor, final Indices indices) { + is_dummy = false; + screen_name = indices.screen_name != -1 ? cursor.getString(indices.screen_name) : null; + name = indices.name != -1 ? cursor.getString(indices.name) : null; + account_id = indices.account_id != -1 ? cursor.getLong(indices.account_id) : -1; + profile_image_url = indices.profile_image_url != -1 ? cursor.getString(indices.profile_image_url) : null; + profile_banner_url = indices.profile_banner_url != -1 ? cursor.getString(indices.profile_banner_url) : null; + color = indices.color != -1 ? cursor.getInt(indices.color) : Color.TRANSPARENT; + is_activated = indices.is_activated != -1 && cursor.getInt(indices.is_activated) == 1; + } + + public ParcelableAccount(final Parcel source) { + is_dummy = source.readInt() == 1; + is_activated = source.readInt() == 1; + account_id = source.readLong(); + name = source.readString(); + screen_name = source.readString(); + profile_image_url = source.readString(); + profile_banner_url = source.readString(); + color = source.readInt(); + } + + private ParcelableAccount() { + is_dummy = true; + screen_name = null; + name = null; + account_id = -1; + profile_image_url = null; + profile_banner_url = null; + color = 0; + is_activated = false; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeInt(is_dummy ? 1 : 0); + out.writeInt(is_activated ? 1 : 0); + out.writeLong(account_id); + out.writeString(name); + out.writeString(screen_name); + out.writeString(profile_image_url); + out.writeString(profile_banner_url); + out.writeInt(color); + } + + public static ParcelableAccount dummyInstance() { + return new ParcelableAccount(); + } + + public static ParcelableAccount getAccount(final Context context, final long account_id) { + if (context == null) return null; + final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI, + Accounts.COLUMNS, Accounts.ACCOUNT_ID + " = " + account_id, null, null); + if (cur != null) { + try { + if (cur.getCount() > 0 && cur.moveToFirst()) { + final Indices indices = new Indices(cur); + cur.moveToFirst(); + return new ParcelableAccount(cur, indices); + } + } finally { + cur.close(); + } + } + return null; + } + + public static long[] getAccountIds(final ParcelableAccount[] accounts) { + final long[] ids = new long[accounts.length]; + for (int i = 0, j = accounts.length; i < j; i++) { + ids[i] = accounts[i].account_id; + } + return ids; + } + + public static ParcelableAccount[] getAccounts(final Context context, final boolean activatedOnly, + final boolean officialKeyOnly) { + final List list = getAccountsList(context, activatedOnly, officialKeyOnly); + return list.toArray(new ParcelableAccount[list.size()]); + } + + @NonNull + public static ParcelableAccount[] getAccounts(@Nullable final Context context, @Nullable final long[] accountIds) { + if (context == null) return new ParcelableAccount[0]; + final String where = accountIds != null ? Expression.in(new Column(Accounts.ACCOUNT_ID), + new RawItemArray(accountIds)).getSQL() : null; + final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI, + Accounts.COLUMNS_NO_CREDENTIALS, where, null, null); + if (cur == null) return new ParcelableAccount[0]; + return getAccounts(cur, new Indices(cur)); + } + + + @NonNull + public static ParcelableAccount[] getAccounts(@Nullable final Cursor cursor) { + if (cursor == null) return new ParcelableAccount[0]; + return getAccounts(cursor, new Indices(cursor)); + } + + @NonNull + public static ParcelableAccount[] getAccounts(@Nullable final Cursor cursor,@Nullable final Indices indices) { + if (cursor == null || indices == null) return new ParcelableAccount[0]; + try { + cursor.moveToFirst(); + final ParcelableAccount[] names = new ParcelableAccount[cursor.getCount()]; + while (!cursor.isAfterLast()) { + names[cursor.getPosition()] = new ParcelableAccount(cursor, indices); + cursor.moveToNext(); + } + return names; + } finally { + cursor.close(); + } + } + + public static List getAccountsList(final Context context, final boolean activatedOnly) { + return getAccountsList(context, activatedOnly, false); + } + + public static List getAccountsList(final Context context, final boolean activatedOnly, + final boolean officialKeyOnly) { + if (context == null) return Collections.emptyList(); + final ArrayList accounts = new ArrayList<>(); + final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), + Accounts.CONTENT_URI, Accounts.COLUMNS, + activatedOnly ? Accounts.IS_ACTIVATED + " = 1" : null, null, Accounts.SORT_POSITION); + if (cur == null) return accounts; + final Indices indices = new Indices(cur); + cur.moveToFirst(); + while (!cur.isAfterLast()) { + if (!officialKeyOnly) { + accounts.add(new ParcelableAccount(cur, indices)); + } else { + final String consumerKey = cur.getString(indices.consumer_key); + final String consumerSecret = cur.getString(indices.consumer_secret); + if (TwitterContentUtils.isOfficialKey(context, consumerKey, consumerSecret)) { + accounts.add(new ParcelableAccount(cur, indices)); + } + } + cur.moveToNext(); + } + cur.close(); + return accounts; + } + + public static ParcelableCredentials getCredentials(final Context context, final long accountId) { + if (context == null) return null; + final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI, + Accounts.COLUMNS, Accounts.ACCOUNT_ID + " = " + accountId, null, null); + if (cur != null) { + try { + if (cur.getCount() > 0 && cur.moveToFirst()) { + final Indices indices = new Indices(cur); + cur.moveToFirst(); + return new ParcelableCredentials(cur, indices); + } + } finally { + cur.close(); + } + } + return null; + } + + public static List getCredentialsList(final Context context, final boolean activatedOnly) { + return getCredentialsList(context, activatedOnly, false); + } + + public static List getCredentialsList(final Context context, final boolean activatedOnly, + final boolean officialKeyOnly) { + if (context == null) return Collections.emptyList(); + final ArrayList accounts = new ArrayList<>(); + final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), + Accounts.CONTENT_URI, Accounts.COLUMNS, + activatedOnly ? Accounts.IS_ACTIVATED + " = 1" : null, null, Accounts.SORT_POSITION); + if (cur == null) return accounts; + final Indices indices = new Indices(cur); + cur.moveToFirst(); + while (!cur.isAfterLast()) { + if (officialKeyOnly) { + final String consumerKey = cur.getString(indices.consumer_key); + final String consumerSecret = cur.getString(indices.consumer_secret); + if (TwitterContentUtils.isOfficialKey(context, consumerKey, consumerSecret)) { + accounts.add(new ParcelableCredentials(cur, indices)); + } + } else { + accounts.add(new ParcelableCredentials(cur, indices)); + } + cur.moveToNext(); + } + cur.close(); + return accounts; + } + + @Override + public String toString() { + return "Account{screen_name=" + screen_name + ", name=" + name + ", profile_image_url=" + profile_image_url + + ", profile_banner_url=" + profile_banner_url + ", account_id=" + account_id + ", color=" + color + + ", is_activated=" + is_activated + ", is_dummy=" + is_dummy + "}"; + } + + public static class ParcelableCredentials extends ParcelableAccount { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + + @Override + public ParcelableCredentials createFromParcel(final Parcel in) { + return new ParcelableCredentials(in); + } + + @Override + public ParcelableCredentials[] newArray(final int size) { + return new ParcelableCredentials[size]; + } + }; + + public final int auth_type; + public final String consumer_key, consumer_secret; + public final String basic_auth_username, basic_auth_password; + public final String oauth_token, oauth_token_secret; + public final String api_url_format; + public final boolean same_oauth_signing_url, no_version_suffix; + + public ParcelableCredentials(final Cursor cursor, final Indices indices) { + super(cursor, indices); + auth_type = cursor.getInt(indices.auth_type); + consumer_key = cursor.getString(indices.consumer_key); + consumer_secret = cursor.getString(indices.consumer_secret); + basic_auth_username = cursor.getString(indices.basic_auth_username); + basic_auth_password = cursor.getString(indices.basic_auth_password); + oauth_token = cursor.getString(indices.oauth_token); + oauth_token_secret = cursor.getString(indices.oauth_token_secret); + api_url_format = cursor.getString(indices.api_url_format); + same_oauth_signing_url = cursor.getInt(indices.same_oauth_signing_url) == 1; + no_version_suffix = cursor.getInt(indices.no_version_suffix) == 1; + } + + public ParcelableCredentials(Parcel in) { + super(in); + auth_type = in.readInt(); + consumer_key = in.readString(); + consumer_secret = in.readString(); + basic_auth_username = in.readString(); + basic_auth_password = in.readString(); + oauth_token = in.readString(); + oauth_token_secret = in.readString(); + api_url_format = in.readString(); + same_oauth_signing_url = in.readInt() == 1; + no_version_suffix = in.readInt() == 1; + } + + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(auth_type); + out.writeString(consumer_key); + out.writeString(consumer_secret); + out.writeString(basic_auth_username); + out.writeString(basic_auth_password); + out.writeString(oauth_token); + out.writeString(oauth_token_secret); + out.writeString(api_url_format); + out.writeInt(same_oauth_signing_url ? 1 : 0); + out.writeInt(no_version_suffix ? 1 : 0); + } + + @Override + public String toString() { + return "AccountWithCredentials{auth_type=" + auth_type + ", consumer_key=" + consumer_key + + ", consumer_secret=" + consumer_secret + ", basic_auth_password=" + basic_auth_password + + ", oauth_token=" + oauth_token + ", oauth_token_secret=" + oauth_token_secret + + ", api_url_format=" + api_url_format + ", same_oauth_signing_url=" + same_oauth_signing_url + "}"; + } + } + + public static final class Indices { + + public final int screen_name, name, account_id, profile_image_url, profile_banner_url, color, is_activated, + auth_type, consumer_key, consumer_secret, basic_auth_username, basic_auth_password, oauth_token, + oauth_token_secret, api_url_format, same_oauth_signing_url, no_version_suffix; + + public Indices(@NonNull final Cursor cursor) { + screen_name = cursor.getColumnIndex(Accounts.SCREEN_NAME); + name = cursor.getColumnIndex(Accounts.NAME); + account_id = cursor.getColumnIndex(Accounts.ACCOUNT_ID); + profile_image_url = cursor.getColumnIndex(Accounts.PROFILE_IMAGE_URL); + profile_banner_url = cursor.getColumnIndex(Accounts.PROFILE_BANNER_URL); + color = cursor.getColumnIndex(Accounts.COLOR); + is_activated = cursor.getColumnIndex(Accounts.IS_ACTIVATED); + auth_type = cursor.getColumnIndex(Accounts.AUTH_TYPE); + consumer_key = cursor.getColumnIndex(Accounts.CONSUMER_KEY); + consumer_secret = cursor.getColumnIndex(Accounts.CONSUMER_SECRET); + basic_auth_username = cursor.getColumnIndex(Accounts.BASIC_AUTH_USERNAME); + basic_auth_password = cursor.getColumnIndex(Accounts.BASIC_AUTH_PASSWORD); + oauth_token = cursor.getColumnIndex(Accounts.OAUTH_TOKEN); + oauth_token_secret = cursor.getColumnIndex(Accounts.OAUTH_TOKEN_SECRET); + api_url_format = cursor.getColumnIndex(Accounts.API_URL_FORMAT); + same_oauth_signing_url = cursor.getColumnIndex(Accounts.SAME_OAUTH_SIGNING_URL); + no_version_suffix = cursor.getColumnIndex(Accounts.NO_VERSION_SUFFIX); + } + + @Override + public String toString() { + return "Indices{screen_name=" + screen_name + ", name=" + name + ", account_id=" + account_id + + ", profile_image_url=" + profile_image_url + ", profile_banner_url=" + profile_banner_url + + ", color=" + color + ", is_activated=" + is_activated + ", auth_type=" + auth_type + + ", consumer_key=" + consumer_key + ", consumer_secret=" + consumer_secret + + ", basic_auth_password=" + basic_auth_password + ", oauth_token=" + oauth_token + + ", oauth_token_secret=" + oauth_token_secret + ", api_url_format=" + api_url_format + + ", same_oauth_signing_url=" + same_oauth_signing_url + "}"; + } + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableDirectMessage.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableDirectMessage.java new file mode 100644 index 00000000..58b100ee --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableDirectMessage.java @@ -0,0 +1,253 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.content.ContentValues; +import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +import org.getlantern.firetweet.provider.TwidereDataStore.DirectMessages; +import org.getlantern.firetweet.util.SimpleValueSerializer; +import org.getlantern.firetweet.util.TwitterContentUtils; + +import java.util.Comparator; +import java.util.Date; + +import twitter4j.DirectMessage; +import twitter4j.User; + +import static org.getlantern.firetweet.util.HtmlEscapeHelper.toPlainText; +import static org.getlantern.firetweet.util.content.ContentValuesUtils.getAsBoolean; +import static org.getlantern.firetweet.util.content.ContentValuesUtils.getAsLong; + +public class ParcelableDirectMessage implements Parcelable, Comparable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableDirectMessage createFromParcel(final Parcel in) { + return new ParcelableDirectMessage(in); + } + + @Override + public ParcelableDirectMessage[] newArray(final int size) { + return new ParcelableDirectMessage[size]; + } + }; + public static final Comparator MESSAGE_ID_COMPARATOR = new Comparator() { + + @Override + public int compare(final ParcelableDirectMessage object1, final ParcelableDirectMessage object2) { + final long diff = object2.id - object1.id; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + }; + + public final long account_id, id, timestamp; + + public final long sender_id, recipient_id; + + public final boolean is_outgoing; + + public final String text_html, text_plain, text_unescaped; + + public final String sender_name, recipient_name, sender_screen_name, recipient_screen_name; + + public final String sender_profile_image_url, recipient_profile_image_url; + + public final ParcelableMedia[] media; + + public ParcelableDirectMessage(final ContentValues values) { + text_plain = values.getAsString(DirectMessages.TEXT_PLAIN); + text_html = values.getAsString(DirectMessages.TEXT_HTML); + text_unescaped = toPlainText(text_html); + sender_screen_name = values.getAsString(DirectMessages.SENDER_SCREEN_NAME); + sender_profile_image_url = values.getAsString(DirectMessages.SENDER_PROFILE_IMAGE_URL); + sender_name = values.getAsString(DirectMessages.SENDER_NAME); + sender_id = getAsLong(values, DirectMessages.SENDER_ID, -1); + recipient_screen_name = values.getAsString(DirectMessages.RECIPIENT_SCREEN_NAME); + recipient_profile_image_url = values.getAsString(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL); + recipient_name = values.getAsString(DirectMessages.RECIPIENT_NAME); + recipient_id = getAsLong(values, DirectMessages.RECIPIENT_ID, -1); + timestamp = getAsLong(values, DirectMessages.MESSAGE_TIMESTAMP, -1); + id = getAsLong(values, DirectMessages.MESSAGE_ID, -1); + is_outgoing = getAsBoolean(values, DirectMessages.IS_OUTGOING, false); + account_id = getAsLong(values, DirectMessages.ACCOUNT_ID, -1); + media = SimpleValueSerializer.fromSerializedString(values.getAsString(DirectMessages.MEDIA_LIST), ParcelableMedia.SIMPLE_CREATOR); + } + + public ParcelableDirectMessage(final Cursor c, final CursorIndices idx) { + account_id = idx.account_id != -1 ? c.getLong(idx.account_id) : -1; + is_outgoing = idx.is_outgoing != -1 ? c.getShort(idx.is_outgoing) == 1 : null; + id = idx.message_id != -1 ? c.getLong(idx.message_id) : -1; + timestamp = idx.message_timestamp != -1 ? c.getLong(idx.message_timestamp) : -1; + sender_id = idx.sender_id != -1 ? c.getLong(idx.sender_id) : -1; + recipient_id = idx.recipient_id != -1 ? c.getLong(idx.recipient_id) : -1; + text_html = idx.text != -1 ? c.getString(idx.text) : null; + text_plain = idx.text_plain != -1 ? c.getString(idx.text_plain) : null; + text_unescaped = toPlainText(text_html); + sender_name = idx.sender_name != -1 ? c.getString(idx.sender_name) : null; + recipient_name = idx.recipient_name != -1 ? c.getString(idx.recipient_name) : null; + sender_screen_name = idx.sender_screen_name != -1 ? c.getString(idx.sender_screen_name) : null; + recipient_screen_name = idx.recipient_screen_name != -1 ? c.getString(idx.recipient_screen_name) : null; + sender_profile_image_url = idx.sender_profile_image_url != -1 ? c.getString(idx.sender_profile_image_url) + : null; + recipient_profile_image_url = idx.recipient_profile_image_url != -1 ? c + .getString(idx.recipient_profile_image_url) : null; + media = SimpleValueSerializer.fromSerializedString(idx.media != -1 ? c.getString(idx.media) : null, ParcelableMedia.SIMPLE_CREATOR); + } + + public ParcelableDirectMessage(final DirectMessage message, final long account_id, final boolean is_outgoing) { + this.account_id = account_id; + this.is_outgoing = is_outgoing; + final User sender = message.getSender(), recipient = message.getRecipient(); + final String sender_profile_image_url = sender != null ? sender.getProfileImageUrlHttps() : null; + final String recipient_profile_image_url = recipient != null ? recipient.getProfileImageUrlHttps() : null; + id = message.getId(); + timestamp = getTime(message.getCreatedAt()); + sender_id = sender != null ? sender.getId() : -1; + recipient_id = recipient != null ? recipient.getId() : -1; + text_html = TwitterContentUtils.formatDirectMessageText(message); + text_plain = message.getText(); + sender_name = sender != null ? sender.getName() : null; + recipient_name = recipient != null ? recipient.getName() : null; + sender_screen_name = sender != null ? sender.getScreenName() : null; + recipient_screen_name = recipient != null ? recipient.getScreenName() : null; + this.sender_profile_image_url = sender_profile_image_url; + this.recipient_profile_image_url = recipient_profile_image_url; + text_unescaped = toPlainText(text_html); + media = ParcelableMedia.fromEntities(message); + } + + public ParcelableDirectMessage(final Parcel in) { + account_id = in.readLong(); + id = in.readLong(); + timestamp = in.readLong(); + sender_id = in.readLong(); + recipient_id = in.readLong(); + is_outgoing = in.readInt() == 1; + text_html = in.readString(); + text_plain = in.readString(); + sender_name = in.readString(); + recipient_name = in.readString(); + sender_screen_name = in.readString(); + recipient_screen_name = in.readString(); + sender_profile_image_url = in.readString(); + recipient_profile_image_url = in.readString(); + text_unescaped = in.readString(); + media = in.createTypedArray(ParcelableMedia.CREATOR); + } + + @Override + public int compareTo(@NonNull final ParcelableDirectMessage another) { + final long diff = another.id - id; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + + @Override + public int describeContents() { + return hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ParcelableDirectMessage)) return false; + final ParcelableDirectMessage other = (ParcelableDirectMessage) obj; + if (account_id != other.account_id) return false; + if (id != other.id) return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (account_id ^ account_id >>> 32); + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "ParcelableDirectMessage{account_id=" + account_id + ", id=" + id + ", timestamp=" + timestamp + + ", sender_id=" + sender_id + ", recipient_id=" + recipient_id + ", is_outgoing=" + is_outgoing + + ", text_html=" + text_html + ", text_plain=" + text_plain + ", text_unescaped=" + text_unescaped + + ", sender_name=" + sender_name + ", recipient_name=" + recipient_name + ", sender_screen_name=" + + sender_screen_name + ", recipient_screen_name=" + recipient_screen_name + + ", sender_profile_image_url=" + sender_profile_image_url + ", recipient_profile_image_url=" + + recipient_profile_image_url + "}"; + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeLong(account_id); + out.writeLong(id); + out.writeLong(timestamp); + out.writeLong(sender_id); + out.writeLong(recipient_id); + out.writeInt(is_outgoing ? 1 : 0); + out.writeString(text_html); + out.writeString(text_plain); + out.writeString(sender_name); + out.writeString(recipient_name); + out.writeString(sender_screen_name); + out.writeString(recipient_screen_name); + out.writeString(sender_profile_image_url); + out.writeString(recipient_profile_image_url); + out.writeString(text_unescaped); + out.writeTypedArray(media, flags); + } + + private static long getTime(final Date date) { + return date != null ? date.getTime() : 0; + } + + public static class CursorIndices { + + public final int account_id, message_id, message_timestamp, sender_name, sender_screen_name, text, text_plain, + recipient_name, recipient_screen_name, sender_profile_image_url, is_outgoing, + recipient_profile_image_url, sender_id, recipient_id, media; + + public CursorIndices(final Cursor cursor) { + account_id = cursor.getColumnIndex(DirectMessages.ACCOUNT_ID); + message_id = cursor.getColumnIndex(DirectMessages.MESSAGE_ID); + message_timestamp = cursor.getColumnIndex(DirectMessages.MESSAGE_TIMESTAMP); + sender_id = cursor.getColumnIndex(DirectMessages.SENDER_ID); + recipient_id = cursor.getColumnIndex(DirectMessages.RECIPIENT_ID); + is_outgoing = cursor.getColumnIndex(DirectMessages.IS_OUTGOING); + text = cursor.getColumnIndex(DirectMessages.TEXT_HTML); + text_plain = cursor.getColumnIndex(DirectMessages.TEXT_PLAIN); + sender_name = cursor.getColumnIndex(DirectMessages.SENDER_NAME); + recipient_name = cursor.getColumnIndex(DirectMessages.RECIPIENT_NAME); + sender_screen_name = cursor.getColumnIndex(DirectMessages.SENDER_SCREEN_NAME); + recipient_screen_name = cursor.getColumnIndex(DirectMessages.RECIPIENT_SCREEN_NAME); + sender_profile_image_url = cursor.getColumnIndex(DirectMessages.SENDER_PROFILE_IMAGE_URL); + recipient_profile_image_url = cursor.getColumnIndex(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL); + media = cursor.getColumnIndex(DirectMessages.MEDIA_LIST); + } + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableLocation.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableLocation.java new file mode 100644 index 00000000..61c8a615 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableLocation.java @@ -0,0 +1,206 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.location.Location; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; +import org.getlantern.firetweet.util.ParseUtils; + +import java.io.Serializable; + +import twitter4j.GeoLocation; + +public class ParcelableLocation implements Serializable, Parcelable, JSONParcelable { + + private static final long serialVersionUID = -1690848439775407442L; + + public final double latitude, longitude; + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableLocation createFromParcel(final Parcel in) { + return new ParcelableLocation(in); + } + + @Override + public ParcelableLocation[] newArray(final int size) { + return new ParcelableLocation[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableLocation createFromParcel(final JSONParcel in) { + return new ParcelableLocation(in); + } + + @Override + public ParcelableLocation[] newArray(final int size) { + return new ParcelableLocation[size]; + } + }; + + public ParcelableLocation(final double latitude, final double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + public ParcelableLocation(@Nullable final GeoLocation location) { + latitude = location != null ? location.getLatitude() : Double.NaN; + longitude = location != null ? location.getLongitude() : Double.NaN; + } + + public ParcelableLocation(@NonNull final JSONParcel in) { + latitude = in.readDouble("latitude", Double.NaN); + longitude = in.readDouble("longitude", Double.NaN); + } + + public ParcelableLocation(@Nullable final Location location) { + latitude = location != null ? location.getLatitude() : Double.NaN; + longitude = location != null ? location.getLongitude() : Double.NaN; + } + + public ParcelableLocation(final Parcel in) { + latitude = in.readDouble(); + longitude = in.readDouble(); + } + + public ParcelableLocation(final String locationString) { + if (locationString == null) { + latitude = Double.NaN; + longitude = Double.NaN; + return; + } + final String[] longlat = locationString.split(","); + if (longlat.length != 2) { + latitude = Double.NaN; + longitude = Double.NaN; + } else { + latitude = ParseUtils.parseDouble(longlat[0], Double.NaN); + longitude = ParseUtils.parseDouble(longlat[1], Double.NaN); + } + } + + @Override + public int describeContents() { + return hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ParcelableLocation)) return false; + final ParcelableLocation other = (ParcelableLocation) obj; + if (Double.doubleToLongBits(latitude) != Double.doubleToLongBits(other.latitude)) + return false; + if (Double.doubleToLongBits(longitude) != Double.doubleToLongBits(other.longitude)) + return false; + return true; + } + + @Nullable + public static ParcelableLocation fromGeoLocation(@Nullable GeoLocation geoLocation) { + if (geoLocation == null) return null; + return new ParcelableLocation(geoLocation); + } + + @Nullable + public static ParcelableLocation fromLocation(@Nullable Location location) { + if (location == null) return null; + return new ParcelableLocation(location); + } + + public String getHumanReadableString(int decimalDigits) { + return String.format("%s,%s", ParseUtils.parsePrettyDecimal(latitude, decimalDigits), + ParseUtils.parsePrettyDecimal(longitude, decimalDigits)); + } + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(latitude); + result = prime * result + (int) (temp ^ temp >>> 32); + temp = Double.doubleToLongBits(longitude); + result = prime * result + (int) (temp ^ temp >>> 32); + return result; + } + + public boolean isValid() { + return isValidLocation(latitude, longitude); + } + + public static boolean isValidLocation(double latitude, double longitude) { + return !Double.isNaN(latitude) && !Double.isNaN(longitude); + } + + public GeoLocation toGeoLocation() { + return isValid() ? new GeoLocation(latitude, longitude) : null; + } + + @Override + public String toString() { + return "ParcelableLocation{latitude=" + latitude + ", longitude=" + longitude + "}"; + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeDouble("latitude", latitude); + out.writeDouble("longitude", longitude); + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeDouble(latitude); + out.writeDouble(longitude); + } + + public static ParcelableLocation fromString(final String string) { + final ParcelableLocation location = new ParcelableLocation(string); + if (ParcelableLocation.isValidLocation(location)) return location; + return null; + } + + public static boolean isValidLocation(final ParcelableLocation location) { + return location != null && location.isValid(); + } + + public static GeoLocation toGeoLocation(final ParcelableLocation location) { + return isValidLocation(location) ? location.toGeoLocation() : null; + } + + public static String toString(final ParcelableLocation location) { + if (!isValidLocation(location)) return null; + return toString(location.latitude, location.longitude); + } + + public static String toString(double latitude, double longitude) { + return latitude + "," + longitude; + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableMedia.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableMedia.java new file mode 100644 index 00000000..8e99ced0 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableMedia.java @@ -0,0 +1,447 @@ +package org.getlantern.firetweet.model; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; +import org.getlantern.firetweet.util.MediaPreviewUtils; +import org.getlantern.firetweet.util.SimpleValueSerializer; +import org.getlantern.firetweet.util.SimpleValueSerializer.Reader; +import org.getlantern.firetweet.util.SimpleValueSerializer.SerializationException; +import org.getlantern.firetweet.util.SimpleValueSerializer.SimpleValueSerializable; +import org.getlantern.firetweet.util.SimpleValueSerializer.Writer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import twitter4j.EntitySupport; +import twitter4j.ExtendedEntitySupport; +import twitter4j.MediaEntity; +import twitter4j.MediaEntity.Size; +import twitter4j.MediaEntity.Type; +import twitter4j.URLEntity; + +@SuppressWarnings("unused") +public class ParcelableMedia implements Parcelable, JSONParcelable, SimpleValueSerializable { + + public static final int TYPE_UNKNOWN = 0; + public static final int TYPE_IMAGE = 1; + public static final int TYPE_VIDEO = 2; + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableMedia createFromParcel(final Parcel in) { + return new ParcelableMedia(in); + } + + @Override + public ParcelableMedia[] newArray(final int size) { + return new ParcelableMedia[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableMedia createFromParcel(final JSONParcel in) { + return new ParcelableMedia(in); + } + + @Override + public ParcelableMedia[] newArray(final int size) { + return new ParcelableMedia[size]; + } + }; + + public static final SimpleValueSerializer.Creator SIMPLE_CREATOR = new SimpleValueSerializer.Creator() { + @Override + public ParcelableMedia create(final SimpleValueSerializer.Reader reader) throws SerializationException { + return new ParcelableMedia(reader); + } + + @Override + public ParcelableMedia[] newArray(final int size) { + return new ParcelableMedia[size]; + } + }; + + @NonNull + public String media_url; + + @Nullable + public String page_url; + public int start, end, type; + public int width, height; + + public VideoInfo video_info; + + + public ParcelableMedia() { + + } + + public ParcelableMedia(final JSONParcel in) { + media_url = in.readString("media_url"); + page_url = in.readString("page_url"); + start = in.readInt("start"); + end = in.readInt("end"); + type = in.readInt("type"); + width = in.readInt("width"); + height = in.readInt("height"); + } + + public ParcelableMedia(final MediaEntity entity) { + page_url = entity.getMediaURL(); + media_url = entity.getMediaURL(); + start = entity.getStart(); + end = entity.getEnd(); + type = getTypeInt(entity.getType()); + final Size size = entity.getSizes().get(Size.LARGE); + width = size != null ? size.getWidth() : 0; + height = size != null ? size.getHeight() : 0; + video_info = VideoInfo.fromMediaEntityInfo(entity.getVideoInfo()); + } + + public ParcelableMedia(ParcelableMediaUpdate update) { + media_url = update.uri; + page_url = update.uri; + type = update.type; + } + + @Nullable + public static ParcelableMedia[] fromMediaUpdates(@Nullable final ParcelableMediaUpdate[] mediaUpdates) { + if (mediaUpdates == null) return null; + final ParcelableMedia[] media = new ParcelableMedia[mediaUpdates.length]; + for (int i = 0, j = mediaUpdates.length; i < j; i++) { + final ParcelableMediaUpdate mediaUpdate = mediaUpdates[i]; + media[i] = new ParcelableMedia(mediaUpdate); + } + return media; + } + + private static int getTypeInt(Type type) { + switch (type) { + case PHOTO: + return TYPE_IMAGE; + case VIDEO: + return TYPE_VIDEO; + } + return TYPE_UNKNOWN; + } + + public ParcelableMedia(final Parcel in) { + page_url = in.readString(); + media_url = in.readString(); + start = in.readInt(); + end = in.readInt(); + type = in.readInt(); + width = in.readInt(); + height = in.readInt(); + video_info = in.readParcelable(VideoInfo.class.getClassLoader()); + } + + private ParcelableMedia(@NonNull final String media_url, @Nullable final String page_url, + final int start, final int end, final int type) { + this.page_url = page_url; + this.media_url = media_url; + this.start = start; + this.end = end; + this.type = type; + this.width = 0; + this.height = 0; + } + + public ParcelableMedia(Reader reader) throws SerializationException { + while (reader.hasKeyValue()) { + switch (reader.nextKey()) { + case "media_url": { + media_url = reader.nextString(); + break; + } + case "page_url": { + page_url = reader.nextString(); + break; + } + case "start": { + start = reader.nextInt(); + break; + } + case "end": { + end = reader.nextInt(); + break; + } + case "type": { + type = reader.nextInt(); + break; + } + case "width": { + width = reader.nextInt(); + break; + } + case "height": { + height = reader.nextInt(); + break; + } + default: { + reader.skipValue(); + break; + } + } + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ParcelableMedia that = (ParcelableMedia) o; + + if (end != that.end) return false; + if (start != that.start) return false; + if (type != that.type) return false; + if (!media_url.equals(that.media_url)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = media_url.hashCode(); + result = 31 * result + start; + result = 31 * result + end; + result = 31 * result + type; + return result; + } + + + @Override + public String toString() { + return "ParcelableMedia{" + + "media_url='" + media_url + '\'' + + ", page_url='" + page_url + '\'' + + ", start=" + start + + ", end=" + end + + ", type=" + type + + ", width=" + width + + ", height=" + height + + '}'; + } + + @Override + public void write(Writer writer) { + writer.write("media_url", media_url); + writer.write("page_url", page_url); + writer.write("start", String.valueOf(start)); + writer.write("end", String.valueOf(end)); + writer.write("type", String.valueOf(type)); + writer.write("width", String.valueOf(width)); + writer.write("height", String.valueOf(height)); + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeString("media_url", media_url); + out.writeString("page_url", page_url); + out.writeInt("start", start); + out.writeInt("end", end); + out.writeInt("type", type); + out.writeInt("width", width); + out.writeInt("height", height); + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeString(page_url); + dest.writeString(media_url); + dest.writeInt(start); + dest.writeInt(end); + dest.writeInt(type); + dest.writeInt(width); + dest.writeInt(height); + dest.writeParcelable(video_info, flags); + } + + public static ParcelableMedia[] fromEntities(final EntitySupport entities) { + final List list = new ArrayList<>(); + final MediaEntity[] mediaEntities; + if (entities instanceof ExtendedEntitySupport) { + final ExtendedEntitySupport extendedEntities = (ExtendedEntitySupport) entities; + final MediaEntity[] extendedMediaEntities = extendedEntities.getExtendedMediaEntities(); + mediaEntities = extendedMediaEntities != null ? extendedMediaEntities : entities.getMediaEntities(); + } else { + mediaEntities = entities.getMediaEntities(); + } + if (mediaEntities != null) { + for (final MediaEntity media : mediaEntities) { + final String mediaURL = media.getMediaURL(); + if (mediaURL != null) { + list.add(new ParcelableMedia(media)); + } + } + } + final URLEntity[] urlEntities = entities.getURLEntities(); + if (urlEntities != null) { + for (final URLEntity url : urlEntities) { + final String expanded = url.getExpandedURL(); + final String media_url = MediaPreviewUtils.getSupportedLink(expanded); + if (expanded != null && media_url != null) { + list.add(new ParcelableMedia(media_url, expanded, url.getStart(), url.getEnd(), TYPE_IMAGE)); + } + } + } + if (list.isEmpty()) return null; + return list.toArray(new ParcelableMedia[list.size()]); + } + + + public static class VideoInfo implements Parcelable { + + public Variant[] variants; + public long[] aspect_ratio; + public long duration; + + public VideoInfo(Reader source) { + + } + + public VideoInfo(MediaEntity.VideoInfo videoInfo) { + variants = Variant.fromMediaEntityVariants(videoInfo.getVariants()); + aspect_ratio = videoInfo.getAspectRatio(); + duration = videoInfo.getDuration(); + } + + public static VideoInfo fromMediaEntityInfo(MediaEntity.VideoInfo videoInfo) { + if (videoInfo == null) return null; + return new VideoInfo(videoInfo); + } + + @Override + public String toString() { + return "VideoInfo{" + + "variants=" + Arrays.toString(variants) + + ", aspect_ratio=" + Arrays.toString(aspect_ratio) + + ", duration=" + duration + + '}'; + } + + public static class Variant implements Parcelable { + public Variant(MediaEntity.VideoInfo.Variant entityVariant) { + content_type = entityVariant.getContentType(); + url = entityVariant.getUrl(); + bitrate = entityVariant.getBitrate(); + } + + @Override + public String toString() { + return "Variant{" + + "content_type='" + content_type + '\'' + + ", url='" + url + '\'' + + ", bitrate=" + bitrate + + '}'; + } + + public final String content_type; + public final String url; + public final long bitrate; + + public Variant(JSONParcel source) { + content_type = source.readString("content_type"); + url = source.readString("url"); + bitrate = source.readLong("bitrate"); + } + + @Override + public int describeContents() { + return 0; + } + + public static Variant[] fromMediaEntityVariants(MediaEntity.VideoInfo.Variant[] entityVariants) { + if (entityVariants == null) return null; + final Variant[] variants = new Variant[entityVariants.length]; + for (int i = 0, j = entityVariants.length; i < j; i++) { + variants[i] = new Variant(entityVariants[i]); + } + return variants; + } + + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.content_type); + dest.writeString(this.url); + dest.writeLong(this.bitrate); + } + + + private Variant(Parcel in) { + this.content_type = in.readString(); + this.url = in.readString(); + this.bitrate = in.readLong(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Variant createFromParcel(Parcel source) { + return new Variant(source); + } + + public Variant[] newArray(int size) { + return new Variant[size]; + } + }; + + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeTypedArray(variants, flags); + dest.writeLongArray(aspect_ratio); + dest.writeLong(duration); + } + + + private VideoInfo(Parcel in) { + variants = in.createTypedArray(Variant.CREATOR); + aspect_ratio = in.createLongArray(); + duration = in.readLong(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public VideoInfo createFromParcel(Parcel source) { + return new VideoInfo(source); + } + + public VideoInfo[] newArray(int size) { + return new VideoInfo[size]; + } + }; + } + + public static ParcelableMedia newImage(final String media_url, final String url) { + return new ParcelableMedia(media_url, url, 0, 0, TYPE_IMAGE); + } + + public static class MediaSize { + + public static final int LARGE = 1; + public static final int MEDIUM = 2; + public static final int SMALL = 3; + public static final int THUMB = 4; + + + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableMediaUpdate.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableMediaUpdate.java new file mode 100644 index 00000000..914a8899 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableMediaUpdate.java @@ -0,0 +1,88 @@ +package org.getlantern.firetweet.model; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; +import org.getlantern.jsonserializer.JSONSerializer; + +public class ParcelableMediaUpdate implements Parcelable, JSONParcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableMediaUpdate createFromParcel(final Parcel in) { + return new ParcelableMediaUpdate(in); + } + + @Override + public ParcelableMediaUpdate[] newArray(final int size) { + return new ParcelableMediaUpdate[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableMediaUpdate createFromParcel(final JSONParcel in) { + return new ParcelableMediaUpdate(in); + } + + @Override + public ParcelableMediaUpdate[] newArray(final int size) { + return new ParcelableMediaUpdate[size]; + } + }; + + public final String uri; + public final int type; + + public ParcelableMediaUpdate(final JSONParcel in) { + uri = in.readString("uri"); + type = in.readInt("type"); + } + + public ParcelableMediaUpdate(final Parcel in) { + uri = in.readString(); + type = in.readInt(); + } + + public ParcelableMediaUpdate(final String uri, final int type) { + this.uri = uri; + this.type = type; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "ParcelableMediaUpdate{uri=" + uri + ", type=" + type + "}"; + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeString("uri", uri); + out.writeInt("type", type); + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeString(uri); + dest.writeInt(type); + } + + public static ParcelableMediaUpdate[] fromJSONString(final String json) { + if (TextUtils.isEmpty(json)) return null; + try { + return JSONSerializer.createArray(JSON_CREATOR, new JSONArray(json)); + } catch (final JSONException e) { + return null; + } + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableStatus.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableStatus.java new file mode 100644 index 00000000..1edd75f4 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableStatus.java @@ -0,0 +1,1082 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import org.json.JSONException; +import org.json.JSONObject; +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; +import org.getlantern.jsonserializer.JSONSerializer; +import org.getlantern.firetweet.provider.TwidereDataStore.Statuses; +import org.getlantern.firetweet.util.HtmlEscapeHelper; +import org.getlantern.firetweet.util.SimpleValueSerializer; +import org.getlantern.firetweet.util.TwitterContentUtils; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; + +import twitter4j.CardEntity; +import twitter4j.CardEntity.BindingValue; +import twitter4j.CardEntity.BooleanValue; +import twitter4j.CardEntity.ImageValue; +import twitter4j.CardEntity.StringValue; +import twitter4j.CardEntity.UserValue; +import twitter4j.Place; +import twitter4j.Status; +import twitter4j.User; + +@SuppressWarnings("unused") +public class ParcelableStatus implements TwidereParcelable, Comparable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableStatus createFromParcel(final Parcel in) { + return new ParcelableStatus(in); + } + + @Override + public ParcelableStatus[] newArray(final int size) { + return new ParcelableStatus[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableStatus createFromParcel(final JSONParcel in) { + return new ParcelableStatus(in); + } + + @Override + public ParcelableStatus[] newArray(final int size) { + return new ParcelableStatus[size]; + } + }; + + public static final Comparator TIMESTAMP_COMPARATOR = new Comparator() { + + @Override + public int compare(final ParcelableStatus object1, final ParcelableStatus object2) { + final long diff = object2.timestamp - object1.timestamp; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + }; + public static final Comparator REVERSE_ID_COMPARATOR = new Comparator() { + + @Override + public int compare(final ParcelableStatus object1, final ParcelableStatus object2) { + final long diff = object1.id - object2.id; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + }; + + public final long id, account_id, timestamp, user_id, retweet_id, retweeted_by_id, retweet_timestamp, + retweet_count, favorite_count, reply_count, descendent_reply_count, in_reply_to_status_id, + in_reply_to_user_id, my_retweet_id, quote_id, quote_timestamp, quoted_by_user_id; + + public final boolean is_gap, is_retweet, is_favorite, is_possibly_sensitive, user_is_following, user_is_protected, + user_is_verified, is_quote, quoted_by_user_is_protected, quoted_by_user_is_verified; + + public final String retweeted_by_name, retweeted_by_screen_name, retweeted_by_profile_image, + text_html, text_plain, user_name, user_screen_name, in_reply_to_name, in_reply_to_screen_name, + source, user_profile_image_url, text_unescaped, card_name, quote_text_html, quote_text_plain, + quote_text_unescaped, quote_source, quoted_by_user_name, quoted_by_user_screen_name, + quoted_by_user_profile_image; + + public final ParcelableLocation location; + + public final String place_full_name; + + public final ParcelableUserMention[] mentions; + + public final ParcelableMedia[] media; + + public final ParcelableCardEntity card; + + public ParcelableStatus(final Cursor c, final CursorIndices idx) { + id = idx.status_id != -1 ? c.getLong(idx.status_id) : -1; + account_id = idx.account_id != -1 ? c.getLong(idx.account_id) : -1; + timestamp = idx.status_timestamp != -1 ? c.getLong(idx.status_timestamp) : 0; + user_id = idx.user_id != -1 ? c.getLong(idx.user_id) : -1; + retweet_id = idx.retweet_id != -1 ? c.getLong(idx.retweet_id) : -1; + retweet_timestamp = idx.retweet_timestamp != -1 ? c.getLong(idx.retweet_timestamp) : -1; + retweeted_by_id = idx.retweeted_by_user_id != -1 ? c.getLong(idx.retweeted_by_user_id) : -1; + retweet_count = idx.retweet_count != -1 ? c.getLong(idx.retweet_count) : -1; + favorite_count = idx.favorite_count != -1 ? c.getLong(idx.favorite_count) : -1; + reply_count = idx.reply_count != -1 ? c.getLong(idx.reply_count) : -1; + descendent_reply_count = idx.descendent_reply_count != -1 ? c.getLong(idx.descendent_reply_count) : -1; + in_reply_to_status_id = idx.in_reply_to_status_id != -1 ? c.getLong(idx.in_reply_to_status_id) : -1; + in_reply_to_user_id = idx.in_reply_to_user_id != -1 ? c.getLong(idx.in_reply_to_user_id) : -1; + is_gap = idx.is_gap != -1 && c.getInt(idx.is_gap) == 1; + is_retweet = idx.is_retweet != -1 && c.getInt(idx.is_retweet) == 1; + is_favorite = idx.is_favorite != -1 && c.getInt(idx.is_favorite) == 1; + user_is_protected = idx.is_protected != -1 && c.getInt(idx.is_protected) == 1; + user_is_verified = idx.is_verified != -1 && c.getInt(idx.is_verified) == 1; + retweeted_by_name = idx.retweeted_by_user_name != -1 ? c.getString(idx.retweeted_by_user_name) : null; + retweeted_by_screen_name = idx.retweeted_by_user_screen_name != -1 ? c + .getString(idx.retweeted_by_user_screen_name) : null; + retweeted_by_profile_image = idx.retweeted_by_user_profile_image != -1 ? c + .getString(idx.retweeted_by_user_profile_image) : null; + text_html = idx.text_html != -1 ? c.getString(idx.text_html) : null; + media = SimpleValueSerializer.fromSerializedString(idx.media != -1 ? c.getString(idx.media) : null, ParcelableMedia.SIMPLE_CREATOR); + text_plain = idx.text_plain != -1 ? c.getString(idx.text_plain) : null; + user_name = idx.user_name != -1 ? c.getString(idx.user_name) : null; + user_screen_name = idx.user_screen_name != -1 ? c.getString(idx.user_screen_name) : null; + in_reply_to_name = idx.in_reply_to_user_name != -1 ? c.getString(idx.in_reply_to_user_name) : null; + in_reply_to_screen_name = idx.in_reply_to_user_screen_name != -1 ? c + .getString(idx.in_reply_to_user_screen_name) : null; + source = idx.source != -1 ? c.getString(idx.source) : null; + location = idx.location != -1 ? new ParcelableLocation(c.getString(idx.location)) : null; + user_profile_image_url = idx.user_profile_image_url != -1 ? c.getString(idx.user_profile_image_url) : null; + text_unescaped = idx.text_unescaped != -1 ? c.getString(idx.text_unescaped) : null; + my_retweet_id = idx.my_retweet_id != -1 ? c.getLong(idx.my_retweet_id) : -1; + is_possibly_sensitive = idx.is_possibly_sensitive != -1 && c.getInt(idx.is_possibly_sensitive) == 1; + user_is_following = idx.is_following != -1 && c.getInt(idx.is_following) == 1; + mentions = idx.mentions != -1 ? ParcelableUserMention.fromJSONString(c.getString(idx.mentions)) : null; + card = idx.card != -1 ? ParcelableCardEntity.fromJSONString(c.getString(idx.card)) : null; + place_full_name = idx.place_full_name != -1 ? c.getString(idx.place_full_name) : null; + is_quote = idx.is_quote != -1 && c.getShort(idx.is_quote) == 1; + quote_id = idx.quote_id != -1 ? c.getLong(idx.quote_id) : -1; + quote_timestamp = idx.quote_timestamp != -1 ? c.getLong(idx.quote_timestamp) : -1; + quoted_by_user_id = idx.quoted_by_user_id != -1 ? c.getLong(idx.quoted_by_user_id) : -1; + quote_text_html = idx.quote_text_html != -1 ? c.getString(idx.quote_text_html) : null; + quote_text_plain = idx.quote_text_plain != -1 ? c.getString(idx.quote_text_plain) : null; + quote_text_unescaped = idx.quote_text_unescaped != -1 ? c.getString(idx.quote_text_unescaped) : null; + quoted_by_user_name = idx.quoted_by_user_name != -1 ? c.getString(idx.quoted_by_user_name) : null; + quoted_by_user_screen_name = idx.quoted_by_user_screen_name != -1 ? c.getString(idx.quoted_by_user_screen_name) : null; + quoted_by_user_profile_image = idx.quoted_by_user_profile_image != -1 ? c.getString(idx.quoted_by_user_profile_image) : null; + quoted_by_user_is_protected = idx.quoted_by_user_is_protected != -1 && c.getShort(idx.quoted_by_user_is_protected) == 1; + quoted_by_user_is_verified = idx.quoted_by_user_is_verified != -1 && c.getShort(idx.quoted_by_user_is_verified) == 1; + quote_source = idx.quote_source != -1 ? c.getString(idx.quote_source) : null; + card_name = card != null ? card.name : null; + } + + public ParcelableStatus(final JSONParcel in) { + id = in.readLong("status_id"); + account_id = in.readLong("account_id"); + timestamp = in.readLong("status_timestamp"); + user_id = in.readLong("user_id"); + retweet_id = in.readLong("retweet_id"); + retweet_timestamp = in.readLong("retweet_timestamp"); + retweeted_by_id = in.readLong("retweeted_by_id"); + retweet_count = in.readLong("retweet_count"); + favorite_count = in.readLong("favorite_count"); + reply_count = in.readLong("reply_count"); + descendent_reply_count = in.readLong("descendent_reply_count"); + in_reply_to_status_id = in.readLong("in_reply_to_status_id"); + in_reply_to_user_id = in.readLong("in_reply_to_user_id"); + is_gap = in.readBoolean("is_gap"); + is_retweet = in.readBoolean("is_retweet"); + is_favorite = in.readBoolean("is_favorite"); + user_is_protected = in.readBoolean("is_protected"); + user_is_verified = in.readBoolean("is_verified"); + retweeted_by_name = in.readString("retweeted_by_name"); + retweeted_by_screen_name = in.readString("retweeted_by_screen_name"); + retweeted_by_profile_image = in.readString("retweeted_by_profile_image"); + text_html = in.readString("text_html"); + text_plain = in.readString("text_plain"); + user_name = in.readString("name"); + user_screen_name = in.readString("screen_name"); + in_reply_to_name = in.readString("in_reply_to_name"); + in_reply_to_screen_name = in.readString("in_reply_to_screen_name"); + source = in.readString("source"); + user_profile_image_url = in.readString("profile_image_url"); + media = in.readParcelableArray("media", ParcelableMedia.JSON_CREATOR); + location = in.readParcelable("location", ParcelableLocation.JSON_CREATOR); + my_retweet_id = in.readLong("my_retweet_id"); + is_possibly_sensitive = in.readBoolean("is_possibly_sensitive"); + text_unescaped = in.readString("text_unescaped"); + user_is_following = in.readBoolean("is_following"); + mentions = in.readParcelableArray("mentions", ParcelableUserMention.JSON_CREATOR); + card = in.readParcelable("card", ParcelableCardEntity.JSON_CREATOR); + place_full_name = in.readString("place_full_name"); + is_quote = in.readBoolean("is_quote"); + quote_id = in.readLong("quote_id"); + quote_text_html = in.readString("quote_text_html"); + quote_text_plain = in.readString("quote_text_plain"); + quote_text_unescaped = in.readString("quote_text_unescaped"); + quote_timestamp = in.readLong("quote_timestamp"); + quoted_by_user_id = in.readLong("quoted_by_user_id"); + quoted_by_user_name = in.readString("quoted_by_user_name"); + quoted_by_user_screen_name = in.readString("quoted_by_user_screen_name"); + quoted_by_user_profile_image = in.readString("quoted_by_user_profile_image"); + quoted_by_user_is_protected = in.readBoolean("quoted_by_user_is_protected"); + quoted_by_user_is_verified = in.readBoolean("quoted_by_user_is_verified"); + quote_source = in.readString("quote_source"); + card_name = card != null ? card.name : null; + } + + public ParcelableStatus(final Parcel in) { + id = in.readLong(); + account_id = in.readLong(); + timestamp = in.readLong(); + user_id = in.readLong(); + retweet_id = in.readLong(); + retweet_timestamp = in.readLong(); + retweeted_by_id = in.readLong(); + retweet_count = in.readLong(); + favorite_count = in.readLong(); + reply_count = in.readLong(); + descendent_reply_count = in.readLong(); + in_reply_to_status_id = in.readLong(); + is_gap = in.readByte() == 1; + is_retweet = in.readByte() == 1; + is_favorite = in.readByte() == 1; + user_is_protected = in.readByte() == 1; + user_is_verified = in.readByte() == 1; + retweeted_by_name = in.readString(); + retweeted_by_screen_name = in.readString(); + retweeted_by_profile_image = in.readString(); + text_html = in.readString(); + text_plain = in.readString(); + user_name = in.readString(); + user_screen_name = in.readString(); + in_reply_to_screen_name = in.readString(); + source = in.readString(); + user_profile_image_url = in.readString(); + media = in.createTypedArray(ParcelableMedia.CREATOR); + location = in.readParcelable(ParcelableLocation.class.getClassLoader()); + my_retweet_id = in.readLong(); + is_possibly_sensitive = in.readByte() == 1; + user_is_following = in.readByte() == 1; + text_unescaped = in.readString(); + in_reply_to_user_id = in.readLong(); + in_reply_to_name = in.readString(); + mentions = in.createTypedArray(ParcelableUserMention.CREATOR); + card = in.readParcelable(ParcelableCardEntity.class.getClassLoader()); + place_full_name = in.readString(); + is_quote = in.readByte() == 1; + quote_id = in.readLong(); + quote_text_html = in.readString(); + quote_text_plain = in.readString(); + quote_text_unescaped = in.readString(); + quote_timestamp = in.readLong(); + quoted_by_user_id = in.readLong(); + quoted_by_user_name = in.readString(); + quoted_by_user_screen_name = in.readString(); + quoted_by_user_profile_image = in.readString(); + quoted_by_user_is_protected = in.readByte() == 1; + quoted_by_user_is_verified = in.readByte() == 1; + quote_source = in.readString(); + card_name = card != null ? card.name : null; + } + + public ParcelableStatus(final ParcelableStatus orig, final long override_my_retweet_id, + final long override_retweet_count) { + id = orig.id; + account_id = orig.account_id; + timestamp = orig.timestamp; + user_id = orig.user_id; + retweet_id = orig.retweet_id; + retweet_timestamp = orig.retweet_timestamp; + retweeted_by_id = orig.retweeted_by_id; + retweet_count = override_retweet_count; + favorite_count = orig.favorite_count; + reply_count = orig.reply_count; + descendent_reply_count = orig.descendent_reply_count; + in_reply_to_status_id = orig.in_reply_to_status_id; + is_gap = orig.is_gap; + is_retweet = orig.is_retweet; + is_favorite = orig.is_favorite; + user_is_protected = orig.user_is_protected; + user_is_verified = orig.user_is_verified; + retweeted_by_name = orig.retweeted_by_name; + retweeted_by_screen_name = orig.retweeted_by_screen_name; + retweeted_by_profile_image = orig.retweeted_by_profile_image; + text_html = orig.text_html; + text_plain = orig.text_plain; + user_name = orig.user_name; + user_screen_name = orig.user_screen_name; + in_reply_to_screen_name = orig.in_reply_to_screen_name; + source = orig.source; + user_profile_image_url = orig.user_profile_image_url; + media = orig.media; + location = orig.location; + my_retweet_id = override_my_retweet_id; + is_possibly_sensitive = orig.is_possibly_sensitive; + user_is_following = orig.user_is_following; + text_unescaped = orig.text_unescaped; + in_reply_to_user_id = orig.in_reply_to_user_id; + in_reply_to_name = orig.in_reply_to_name; + mentions = orig.mentions; + card = orig.card; + place_full_name = orig.place_full_name; + is_quote = orig.is_quote; + quote_id = orig.quote_id; + quote_timestamp = orig.quote_timestamp; + quoted_by_user_id = orig.quoted_by_user_id; + quoted_by_user_name = orig.quoted_by_user_name; + quoted_by_user_screen_name = orig.quoted_by_user_screen_name; + quoted_by_user_profile_image = orig.quoted_by_user_profile_image; + quote_text_html = orig.quote_text_html; + quote_text_plain = orig.quote_text_plain; + quote_text_unescaped = orig.quote_text_unescaped; + quote_source = orig.quote_source; + quoted_by_user_is_protected = orig.quoted_by_user_is_protected; + quoted_by_user_is_verified = orig.quoted_by_user_is_verified; + card_name = card != null ? card.name : null; + } + + public ParcelableStatus(final Status orig, final long account_id, final boolean is_gap) { + this.is_gap = is_gap; + this.account_id = account_id; + id = orig.getId(); + timestamp = getTime(orig.getCreatedAt()); + + final Status retweeted = orig.getRetweetedStatus(); + final User retweet_user = retweeted != null ? orig.getUser() : null; + is_retweet = orig.isRetweet(); + retweet_id = retweeted != null ? retweeted.getId() : -1; + retweet_timestamp = retweeted != null ? getTime(retweeted.getCreatedAt()) : -1; + retweeted_by_id = retweet_user != null ? retweet_user.getId() : -1; + retweeted_by_name = retweet_user != null ? retweet_user.getName() : null; + retweeted_by_screen_name = retweet_user != null ? retweet_user.getScreenName() : null; + retweeted_by_profile_image = retweet_user != null ? retweet_user.getProfileImageUrlHttps() : null; + + final Status quoted = orig.getQuotedStatus(); + final User quote_user = quoted != null ? orig.getUser() : null; + is_quote = orig.isQuote(); + quote_id = quoted != null ? quoted.getId() : -1; + quote_text_html = TwitterContentUtils.formatStatusText(orig); + quote_text_plain = orig.getText(); + quote_text_unescaped = HtmlEscapeHelper.toPlainText(quote_text_html); + quote_timestamp = orig.getCreatedAt().getTime(); + quote_source = orig.getSource(); + + quoted_by_user_id = quote_user != null ? quote_user.getId() : -1; + quoted_by_user_name = quote_user != null ? quote_user.getName() : null; + quoted_by_user_screen_name = quote_user != null ? quote_user.getScreenName() : null; + quoted_by_user_profile_image = quote_user != null ? quote_user.getProfileImageUrlHttps() : null; + quoted_by_user_is_protected = quote_user != null && quote_user.isProtected(); + quoted_by_user_is_verified = quote_user != null && quote_user.isVerified(); + + final Status status; + if (quoted != null) { + status = quoted; + } else if (retweeted != null) { + status = retweeted; + } else { + status = orig; + } + final User user = status.getUser(); + user_id = user.getId(); + user_name = user.getName(); + user_screen_name = user.getScreenName(); + user_profile_image_url = user.getProfileImageUrlHttps(); + user_is_protected = user.isProtected(); + user_is_verified = user.isVerified(); + user_is_following = user.isFollowing(); + text_html = TwitterContentUtils.formatStatusText(status); + media = ParcelableMedia.fromEntities(status); + text_plain = status.getText(); + retweet_count = status.getRetweetCount(); + favorite_count = status.getFavoriteCount(); + reply_count = status.getReplyCount(); + descendent_reply_count = status.getDescendentReplyCount(); + in_reply_to_name = TwitterContentUtils.getInReplyToName(status); + in_reply_to_screen_name = status.getInReplyToScreenName(); + in_reply_to_status_id = status.getInReplyToStatusId(); + in_reply_to_user_id = status.getInReplyToUserId(); + source = status.getSource(); + location = ParcelableLocation.fromGeoLocation(status.getGeoLocation()); + is_favorite = status.isFavorited(); + text_unescaped = HtmlEscapeHelper.toPlainText(text_html); + my_retweet_id = retweeted_by_id == account_id ? id : status.getCurrentUserRetweet(); + is_possibly_sensitive = status.isPossiblySensitive(); + mentions = ParcelableUserMention.fromUserMentionEntities(status.getUserMentionEntities()); + card = ParcelableCardEntity.fromCardEntity(status.getCard(), account_id); + place_full_name = getPlaceFullName(status.getPlace()); + card_name = card != null ? card.name : null; + } + + @Override + public int compareTo(@NonNull final ParcelableStatus another) { + final long diff = another.id - id; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ParcelableStatus)) return false; + final ParcelableStatus other = (ParcelableStatus) obj; + return account_id == other.account_id && id == other.id; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (account_id ^ account_id >>> 32); + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "ParcelableStatus{" + + "id=" + id + + ", account_id=" + account_id + + ", timestamp=" + timestamp + + ", user_id=" + user_id + + ", retweet_id=" + retweet_id + + ", retweeted_by_id=" + retweeted_by_id + + ", retweet_timestamp=" + retweet_timestamp + + ", retweet_count=" + retweet_count + + ", favorite_count=" + favorite_count + + ", reply_count=" + reply_count + + ", descendent_reply_count=" + descendent_reply_count + + ", in_reply_to_status_id=" + in_reply_to_status_id + + ", in_reply_to_user_id=" + in_reply_to_user_id + + ", my_retweet_id=" + my_retweet_id + + ", quote_id=" + quote_id + + ", quote_timestamp=" + quote_timestamp + + ", quoted_by_user_id=" + quoted_by_user_id + + ", is_gap=" + is_gap + + ", is_retweet=" + is_retweet + + ", is_favorite=" + is_favorite + + ", is_possibly_sensitive=" + is_possibly_sensitive + + ", user_is_following=" + user_is_following + + ", user_is_protected=" + user_is_protected + + ", user_is_verified=" + user_is_verified + + ", is_quote=" + is_quote + + ", quoted_by_user_is_protected=" + quoted_by_user_is_protected + + ", quoted_by_user_is_verified=" + quoted_by_user_is_verified + + ", retweeted_by_name='" + retweeted_by_name + '\'' + + ", retweeted_by_screen_name='" + retweeted_by_screen_name + '\'' + + ", retweeted_by_profile_image='" + retweeted_by_profile_image + '\'' + + ", text_html='" + text_html + '\'' + + ", text_plain='" + text_plain + '\'' + + ", user_name='" + user_name + '\'' + + ", user_screen_name='" + user_screen_name + '\'' + + ", in_reply_to_name='" + in_reply_to_name + '\'' + + ", in_reply_to_screen_name='" + in_reply_to_screen_name + '\'' + + ", source='" + source + '\'' + + ", user_profile_image_url='" + user_profile_image_url + '\'' + + ", text_unescaped='" + text_unescaped + '\'' + + ", card_name='" + card_name + '\'' + + ", quote_text_html='" + quote_text_html + '\'' + + ", quote_text_plain='" + quote_text_plain + '\'' + + ", quote_text_unescaped='" + quote_text_unescaped + '\'' + + ", quote_source='" + quote_source + '\'' + + ", quoted_by_user_name='" + quoted_by_user_name + '\'' + + ", quoted_by_user_screen_name='" + quoted_by_user_screen_name + '\'' + + ", quoted_by_user_profile_image='" + quoted_by_user_profile_image + '\'' + + ", location=" + location + + ", place_full_name='" + place_full_name + '\'' + + ", mentions=" + Arrays.toString(mentions) + + ", media=" + Arrays.toString(media) + + ", card=" + card + + '}'; + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeLong("status_id", id); + out.writeLong("account_id", account_id); + out.writeLong("status_timestamp", timestamp); + out.writeLong("user_id", user_id); + out.writeLong("retweet_id", retweet_id); + out.writeLong("retweet_timestamp", retweet_timestamp); + out.writeLong("retweeted_by_id", retweeted_by_id); + out.writeLong("retweet_count", retweet_count); + out.writeLong("favorite_count", favorite_count); + out.writeLong("reply_count", reply_count); + out.writeLong("descendent_reply_count", descendent_reply_count); + out.writeLong("in_reply_to_status_id", in_reply_to_status_id); + out.writeLong("in_reply_to_user_id", in_reply_to_user_id); + out.writeBoolean("is_gap", is_gap); + out.writeBoolean("is_retweet", is_retweet); + out.writeBoolean("is_favorite", is_favorite); + out.writeBoolean("is_protected", user_is_protected); + out.writeBoolean("is_verified", user_is_verified); + out.writeString("retweeted_by_name", retweeted_by_name); + out.writeString("retweeted_by_screen_name", retweeted_by_screen_name); + out.writeString("retweeted_by_profile_image", retweeted_by_profile_image); + out.writeString("text_html", text_html); + out.writeString("text_plain", text_plain); + out.writeString("text_unescaped", text_unescaped); + out.writeString("name", user_name); + out.writeString("screen_name", user_screen_name); + out.writeString("in_reply_to_name", in_reply_to_name); + out.writeString("in_reply_to_screen_name", in_reply_to_screen_name); + out.writeString("source", source); + out.writeString("profile_image_url", user_profile_image_url); + out.writeParcelableArray("media", media); + out.writeParcelable("location", location); + out.writeLong("my_retweet_id", my_retweet_id); + out.writeBoolean("is_possibly_sensitive", is_possibly_sensitive); + out.writeBoolean("is_following", user_is_following); + out.writeParcelableArray("mentions", mentions); + out.writeParcelable("card", card); + out.writeString("place_full_name", place_full_name); + out.writeBoolean("is_quote", is_quote); + out.writeLong("quote_id", quote_id); + out.writeString("quote_text_html", quote_text_html); + out.writeString("quote_text_plain", quote_text_plain); + out.writeString("quote_text_unescaped", quote_text_unescaped); + out.writeLong("quote_timestamp", quote_timestamp); + out.writeLong("quoted_by_user_id", quoted_by_user_id); + out.writeString("quoted_by_user_name", quoted_by_user_name); + out.writeString("quoted_by_user_screen_name", quoted_by_user_screen_name); + out.writeString("quoted_by_user_profile_image", quoted_by_user_profile_image); + out.writeBoolean("quoted_by_user_is_protected", quoted_by_user_is_protected); + out.writeBoolean("quoted_by_user_is_verified", quoted_by_user_is_verified); + out.writeString("quote_source", quote_source); + } + + @Nullable + private static String getPlaceFullName(@Nullable Place place) { + if (place == null) return null; + return place.getFullName(); + } + + private static long getTime(final Date date) { + return date != null ? date.getTime() : 0; + } + + public static final class CursorIndices { + + public final int _id, account_id, status_id, status_timestamp, user_name, user_screen_name, + text_html, text_plain, text_unescaped, user_profile_image_url, is_favorite, is_retweet, + is_gap, location, is_protected, is_verified, in_reply_to_status_id, in_reply_to_user_id, + in_reply_to_user_name, in_reply_to_user_screen_name, my_retweet_id, retweeted_by_user_name, + retweeted_by_user_screen_name, retweeted_by_user_profile_image, retweet_id, retweet_timestamp, + retweeted_by_user_id, user_id, source, retweet_count, favorite_count, reply_count, + descendent_reply_count, is_possibly_sensitive, is_following, media, mentions, card_name, + card, place_full_name, is_quote, quote_id, quote_text_html, quote_text_plain, quote_text_unescaped, + quote_timestamp, quote_source, quoted_by_user_id, quoted_by_user_name, quoted_by_user_screen_name, + quoted_by_user_profile_image, quoted_by_user_is_protected, quoted_by_user_is_verified; + + public CursorIndices(final Cursor cursor) { + _id = cursor.getColumnIndex(Statuses._ID); + account_id = cursor.getColumnIndex(Statuses.ACCOUNT_ID); + status_id = cursor.getColumnIndex(Statuses.STATUS_ID); + status_timestamp = cursor.getColumnIndex(Statuses.STATUS_TIMESTAMP); + user_name = cursor.getColumnIndex(Statuses.USER_NAME); + user_screen_name = cursor.getColumnIndex(Statuses.USER_SCREEN_NAME); + text_html = cursor.getColumnIndex(Statuses.TEXT_HTML); + text_plain = cursor.getColumnIndex(Statuses.TEXT_PLAIN); + text_unescaped = cursor.getColumnIndex(Statuses.TEXT_UNESCAPED); + user_profile_image_url = cursor.getColumnIndex(Statuses.USER_PROFILE_IMAGE_URL); + is_favorite = cursor.getColumnIndex(Statuses.IS_FAVORITE); + is_retweet = cursor.getColumnIndex(Statuses.IS_RETWEET); + is_quote = cursor.getColumnIndex(Statuses.IS_QUOTE); + is_gap = cursor.getColumnIndex(Statuses.IS_GAP); + location = cursor.getColumnIndex(Statuses.LOCATION); + is_protected = cursor.getColumnIndex(Statuses.IS_PROTECTED); + is_verified = cursor.getColumnIndex(Statuses.IS_VERIFIED); + in_reply_to_status_id = cursor.getColumnIndex(Statuses.IN_REPLY_TO_STATUS_ID); + in_reply_to_user_id = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_ID); + in_reply_to_user_name = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_NAME); + in_reply_to_user_screen_name = cursor.getColumnIndex(Statuses.IN_REPLY_TO_USER_SCREEN_NAME); + my_retweet_id = cursor.getColumnIndex(Statuses.MY_RETWEET_ID); + retweet_id = cursor.getColumnIndex(Statuses.RETWEET_ID); + retweet_timestamp = cursor.getColumnIndex(Statuses.RETWEET_TIMESTAMP); + retweeted_by_user_id = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_ID); + retweeted_by_user_name = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_NAME); + retweeted_by_user_screen_name = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_SCREEN_NAME); + retweeted_by_user_profile_image = cursor.getColumnIndex(Statuses.RETWEETED_BY_USER_PROFILE_IMAGE); + quote_id = cursor.getColumnIndex(Statuses.QUOTE_ID); + quote_text_html = cursor.getColumnIndex(Statuses.QUOTE_TEXT_HTML); + quote_text_plain = cursor.getColumnIndex(Statuses.QUOTE_TEXT_PLAIN); + quote_text_unescaped = cursor.getColumnIndex(Statuses.QUOTE_TEXT_UNESCAPED); + quote_timestamp = cursor.getColumnIndex(Statuses.QUOTE_TIMESTAMP); + quote_source = cursor.getColumnIndex(Statuses.QUOTE_SOURCE); + quoted_by_user_id = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_ID); + quoted_by_user_name = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_NAME); + quoted_by_user_screen_name = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_SCREEN_NAME); + quoted_by_user_profile_image = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_PROFILE_IMAGE); + quoted_by_user_is_protected = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_IS_PROTECTED); + quoted_by_user_is_verified = cursor.getColumnIndex(Statuses.QUOTED_BY_USER_IS_VERIFIED); + user_id = cursor.getColumnIndex(Statuses.USER_ID); + source = cursor.getColumnIndex(Statuses.SOURCE); + retweet_count = cursor.getColumnIndex(Statuses.RETWEET_COUNT); + favorite_count = cursor.getColumnIndex(Statuses.FAVORITE_COUNT); + reply_count = cursor.getColumnIndex(Statuses.REPLY_COUNT); + descendent_reply_count = cursor.getColumnIndex(Statuses.DESCENDENT_REPLY_COUNT); + is_possibly_sensitive = cursor.getColumnIndex(Statuses.IS_POSSIBLY_SENSITIVE); + is_following = cursor.getColumnIndex(Statuses.IS_FOLLOWING); + media = cursor.getColumnIndex(Statuses.MEDIA_LIST); + mentions = cursor.getColumnIndex(Statuses.MENTIONS_LIST); + card = cursor.getColumnIndex(Statuses.CARD); + card_name = cursor.getColumnIndex(Statuses.CARD_NAME); + place_full_name = cursor.getColumnIndex(Statuses.PLACE_FULL_NAME); + } + + @Override + public String toString() { + return "CursorIndices{" + + "_id=" + _id + + ", account_id=" + account_id + + ", status_id=" + status_id + + ", status_timestamp=" + status_timestamp + + ", user_name=" + user_name + + ", user_screen_name=" + user_screen_name + + ", text_html=" + text_html + + ", text_plain=" + text_plain + + ", text_unescaped=" + text_unescaped + + ", user_profile_image_url=" + user_profile_image_url + + ", is_favorite=" + is_favorite + + ", is_retweet=" + is_retweet + + ", is_gap=" + is_gap + + ", location=" + location + + ", is_protected=" + is_protected + + ", is_verified=" + is_verified + + ", in_reply_to_status_id=" + in_reply_to_status_id + + ", in_reply_to_user_id=" + in_reply_to_user_id + + ", in_reply_to_user_name=" + in_reply_to_user_name + + ", in_reply_to_user_screen_name=" + in_reply_to_user_screen_name + + ", my_retweet_id=" + my_retweet_id + + ", retweeted_by_user_name=" + retweeted_by_user_name + + ", retweeted_by_user_screen_name=" + retweeted_by_user_screen_name + + ", retweeted_by_user_profile_image=" + retweeted_by_user_profile_image + + ", retweet_id=" + retweet_id + + ", retweet_timestamp=" + retweet_timestamp + + ", retweeted_by_user_id=" + retweeted_by_user_id + + ", user_id=" + user_id + + ", source=" + source + + ", retweet_count=" + retweet_count + + ", favorite_count=" + favorite_count + + ", reply_count=" + reply_count + + ", descendent_reply_count=" + descendent_reply_count + + ", is_possibly_sensitive=" + is_possibly_sensitive + + ", is_following=" + is_following + + ", media=" + media + + ", mentions=" + mentions + + ", card_name=" + card_name + + ", card=" + card + + ", place_full_name=" + place_full_name + + '}'; + } + + + } + + public static final class ParcelableCardEntity implements TwidereParcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableCardEntity createFromParcel(final Parcel in) { + return new ParcelableCardEntity(in); + } + + @Override + public ParcelableCardEntity[] newArray(final int size) { + return new ParcelableCardEntity[size]; + } + }; + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableCardEntity createFromParcel(final JSONParcel in) { + return new ParcelableCardEntity(in); + } + + @Override + public ParcelableCardEntity[] newArray(final int size) { + return new ParcelableCardEntity[size]; + } + }; + + public final String name; + public final ParcelableUser[] users; + public final ParcelableValueItem[] values; + + public ParcelableCardEntity(Parcel src) { + name = src.readString(); + values = src.createTypedArray(ParcelableValueItem.CREATOR); + users = src.createTypedArray(ParcelableUser.CREATOR); + } + + public ParcelableCardEntity(JSONParcel src) { + name = src.readString("name"); + values = src.readParcelableArray("values", ParcelableValueItem.JSON_CREATOR); + users = src.readParcelableArray("users", ParcelableUser.JSON_CREATOR); + } + + public ParcelableCardEntity(CardEntity card, long account_id) { + name = card.getName(); + users = ParcelableUser.fromUsersArray(card.gerUsers(), account_id); + final BindingValue[] bindingValues = card.getBindingValues(); + if (bindingValues != null) { + values = new ParcelableValueItem[bindingValues.length]; + for (int i = 0, j = bindingValues.length; i < j; i++) { + values[i] = new ParcelableValueItem(bindingValues[i]); + } + } else { + values = null; + } + } + + @Override + public String toString() { + return "ParcelableCardEntity{" + + "name='" + name + '\'' + + ", users=" + Arrays.toString(users) + + ", values=" + Arrays.toString(values) + + '}'; + } + + public static ParcelableCardEntity fromCardEntity(CardEntity card, long account_id) { + if (card == null) return null; + return new ParcelableCardEntity(card, account_id); + } + + public static ParcelableCardEntity fromJSONString(final String json) { + if (TextUtils.isEmpty(json)) return null; + try { + return JSONSerializer.createObject(JSON_CREATOR, new JSONObject(json)); + } catch (final JSONException e) { + return null; + } + } + + public static ParcelableValueItem getValue(ParcelableCardEntity entity, String key) { + for (ParcelableValueItem item : entity.values) { + if (item.name.equals(key)) return item; + } + return null; + } + + public static final class ParcelableImageValue implements TwidereParcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableImageValue createFromParcel(final Parcel in) { + return new ParcelableImageValue(in); + } + + @Override + public ParcelableImageValue[] newArray(final int size) { + return new ParcelableImageValue[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableImageValue createFromParcel(final JSONParcel in) { + return new ParcelableImageValue(in); + } + + @Override + public ParcelableImageValue[] newArray(final int size) { + return new ParcelableImageValue[size]; + } + }; + public final int width, height; + public final String url; + + public ParcelableImageValue(JSONParcel in) { + this.width = in.readInt("width"); + this.height = in.readInt("height"); + this.url = in.readString("url"); + } + + public ParcelableImageValue(Parcel in) { + this.width = in.readInt(); + this.height = in.readInt(); + this.url = in.readString(); + } + + public ParcelableImageValue(ImageValue value) { + this.width = value.getWidth(); + this.height = value.getHeight(); + this.url = value.getUrl(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(width); + dest.writeInt(height); + dest.writeString(url); + } + + @Override + public void writeToParcel(JSONParcel dest) { + dest.writeInt("width", width); + dest.writeInt("height", height); + dest.writeString("url", url); + } + } + + public static final class ParcelableUserValue implements TwidereParcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableUserValue createFromParcel(final Parcel in) { + return new ParcelableUserValue(in); + } + + @Override + public ParcelableUserValue[] newArray(final int size) { + return new ParcelableUserValue[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableUserValue createFromParcel(final JSONParcel in) { + return new ParcelableUserValue(in); + } + + @Override + public ParcelableUserValue[] newArray(final int size) { + return new ParcelableUserValue[size]; + } + }; + public final long id; + + public ParcelableUserValue(JSONParcel in) { + this.id = in.readLong("id"); + } + + public ParcelableUserValue(Parcel in) { + this.id = in.readLong(); + } + + public ParcelableUserValue(UserValue value) { + this.id = value.getUserId(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + } + + @Override + public void writeToParcel(JSONParcel dest) { + dest.writeLong("id", id); + } + } + + public static final class ParcelableValueItem implements TwidereParcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableValueItem createFromParcel(final Parcel in) { + return new ParcelableValueItem(in); + } + + @Override + public ParcelableValueItem[] newArray(final int size) { + return new ParcelableValueItem[size]; + } + }; + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableValueItem createFromParcel(final JSONParcel in) { + return new ParcelableValueItem(in); + } + + @Override + public ParcelableValueItem[] newArray(final int size) { + return new ParcelableValueItem[size]; + } + }; + + public final String name, type; + public final Object value; + + public ParcelableValueItem(JSONParcel in) { + this.name = in.readString("name"); + this.type = in.readString("type"); + switch (type) { + case BindingValue.TYPE_STRING: + value = in.readString("value"); + break; + case BindingValue.TYPE_BOOLEAN: + value = in.readBoolean("value"); + break; + case BindingValue.TYPE_IMAGE: + value = in.readParcelable("value", ParcelableImageValue.JSON_CREATOR); + break; + case BindingValue.TYPE_USER: + value = in.readParcelable("value", ParcelableUserValue.JSON_CREATOR); + break; + default: + throw new UnsupportedOperationException(); + } + } + + public ParcelableValueItem(Parcel in) { + this.name = in.readString(); + this.type = in.readString(); + this.value = in.readValue(ParcelableValueItem.class.getClassLoader()); + } + + public ParcelableValueItem(BindingValue bindingValue) { + name = bindingValue.getName(); + type = bindingValue.getType(); + switch (type) { + case BindingValue.TYPE_STRING: + value = ((StringValue) bindingValue).getValue(); + break; + case BindingValue.TYPE_BOOLEAN: + value = ((BooleanValue) bindingValue).getValue(); + break; + case BindingValue.TYPE_IMAGE: + value = new ParcelableImageValue((ImageValue) bindingValue); + break; + case BindingValue.TYPE_USER: + value = new ParcelableUserValue((UserValue) bindingValue); + break; + default: + value = null; + break; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "ParcelableValueItem{" + + "name='" + name + '\'' + + ", type='" + type + '\'' + + ", value=" + value + + '}'; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(name); + dest.writeString(type); + dest.writeValue(value); + } + + @Override + public void writeToParcel(JSONParcel dest) { + dest.writeString("name", name); + dest.writeString("type", type); + dest.writeObject("value", value); + } + } + + + @Override + public int describeContents() { + return 0; + } + + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(name); + dest.writeTypedArray(values, flags); + dest.writeTypedArray(users, flags); + } + + @Override + public void writeToParcel(JSONParcel dest) { + dest.writeString("name", name); + dest.writeParcelableArray("values", values); + dest.writeParcelableArray("users", users); + } + + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeLong(id); + out.writeLong(account_id); + out.writeLong(timestamp); + out.writeLong(user_id); + out.writeLong(retweet_id); + out.writeLong(retweet_timestamp); + out.writeLong(retweeted_by_id); + out.writeLong(retweet_count); + out.writeLong(favorite_count); + out.writeLong(reply_count); + out.writeLong(descendent_reply_count); + out.writeLong(in_reply_to_status_id); + out.writeByte((byte) (is_gap ? 1 : 0)); + out.writeByte((byte) (is_retweet ? 1 : 0)); + out.writeByte((byte) (is_favorite ? 1 : 0)); + out.writeByte((byte) (user_is_protected ? 1 : 0)); + out.writeByte((byte) (user_is_verified ? 1 : 0)); + out.writeString(retweeted_by_name); + out.writeString(retweeted_by_screen_name); + out.writeString(retweeted_by_profile_image); + out.writeString(text_html); + out.writeString(text_plain); + out.writeString(user_name); + out.writeString(user_screen_name); + out.writeString(in_reply_to_screen_name); + out.writeString(source); + out.writeString(user_profile_image_url); + out.writeTypedArray(media, flags); + out.writeParcelable(location, flags); + out.writeLong(my_retweet_id); + out.writeByte((byte) (is_possibly_sensitive ? 1 : 0)); + out.writeByte((byte) (user_is_following ? 1 : 0)); + out.writeString(text_unescaped); + out.writeLong(in_reply_to_user_id); + out.writeString(in_reply_to_name); + out.writeTypedArray(mentions, flags); + out.writeParcelable(card, flags); + out.writeString(place_full_name); + out.writeByte((byte) (is_quote ? 1 : 0)); + out.writeLong(quote_id); + out.writeString(quote_text_html); + out.writeString(quote_text_plain); + out.writeString(quote_text_unescaped); + out.writeLong(quote_timestamp); + out.writeLong(quoted_by_user_id); + out.writeString(quoted_by_user_name); + out.writeString(quoted_by_user_screen_name); + out.writeString(quoted_by_user_profile_image); + out.writeByte((byte) (quoted_by_user_is_protected ? 1 : 0)); + out.writeByte((byte) (quoted_by_user_is_verified ? 1 : 0)); + out.writeString(quote_source); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableStatusUpdate.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableStatusUpdate.java new file mode 100644 index 00000000..264f4442 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableStatusUpdate.java @@ -0,0 +1,162 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; + +public class ParcelableStatusUpdate implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableStatusUpdate createFromParcel(final Parcel in) { + return new ParcelableStatusUpdate(in); + } + + @Override + public ParcelableStatusUpdate[] newArray(final int size) { + return new ParcelableStatusUpdate[size]; + } + }; + + public final ParcelableAccount[] accounts; + public final ParcelableMediaUpdate[] media; + public final String text; + public final ParcelableLocation location; + public final long in_reply_to_status_id; + public final boolean is_possibly_sensitive; + + /** + * @deprecated It has too much arguments to call, use + * ParcelableStatusUpdate.Builder instead. + */ + @Deprecated + public ParcelableStatusUpdate(final ParcelableAccount[] accounts, final String text, final ParcelableLocation location, + final ParcelableMediaUpdate[] media, final long in_reply_to_status_id, final boolean is_possibly_sensitive) { + this.accounts = accounts; + this.text = text; + this.location = location; + this.media = media; + this.in_reply_to_status_id = in_reply_to_status_id; + this.is_possibly_sensitive = is_possibly_sensitive; + } + + public ParcelableStatusUpdate(final Context context, final DraftItem draft) { + accounts = ParcelableAccount.getAccounts(context, draft.account_ids); + text = draft.text; + location = draft.location; + media = draft.media; + in_reply_to_status_id = draft.in_reply_to_status_id; + is_possibly_sensitive = draft.is_possibly_sensitive; + } + + public ParcelableStatusUpdate(final Parcel in) { + accounts = in.createTypedArray(ParcelableAccount.CREATOR); + text = in.readString(); + location = in.readParcelable(ParcelableLocation.class.getClassLoader()); + media = in.createTypedArray(ParcelableMediaUpdate.CREATOR); + in_reply_to_status_id = in.readLong(); + is_possibly_sensitive = in.readInt() == 1; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "ParcelableStatusUpdate{accounts=" + Arrays.toString(accounts) + ", media=" + Arrays.toString(media) + + ", text=" + text + ", location=" + location + ", in_reply_to_status_id=" + in_reply_to_status_id + + ", is_possibly_sensitive=" + is_possibly_sensitive + "}"; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeTypedArray(accounts, flags); + dest.writeString(text); + dest.writeParcelable(location, flags); + dest.writeTypedArray(media, flags); + dest.writeLong(in_reply_to_status_id); + dest.writeInt(is_possibly_sensitive ? 1 : 0); + } + + public static final class Builder { + + private ParcelableAccount[] accounts; + private String text; + private ParcelableLocation location; + private ParcelableMediaUpdate[] media; + private long in_reply_to_status_id; + private boolean is_possibly_sensitive; + + public Builder() { + + } + + public Builder(final ParcelableStatusUpdate base) { + accounts(base.accounts); + text(base.text); + media(base.media); + location(base.location); + inReplyToStatusId(base.in_reply_to_status_id); + isPossiblySensitive(base.is_possibly_sensitive); + } + + public Builder accounts(final ParcelableAccount[] accounts) { + this.accounts = accounts; + return this; + } + + public ParcelableStatusUpdate build() { + return new ParcelableStatusUpdate(accounts, text, location, media, in_reply_to_status_id, + is_possibly_sensitive); + } + + public Builder inReplyToStatusId(final long in_reply_to_status_id) { + this.in_reply_to_status_id = in_reply_to_status_id; + return this; + } + + public Builder isPossiblySensitive(final boolean is_possibly_sensitive) { + this.is_possibly_sensitive = is_possibly_sensitive; + return this; + } + + public Builder location(final ParcelableLocation location) { + this.location = location; + return this; + } + + public Builder media(final ParcelableMediaUpdate... media) { + this.media = media; + return this; + } + + public Builder text(final String text) { + this.text = text; + return this; + } + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUser.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUser.java new file mode 100644 index 00000000..b5b557eb --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUser.java @@ -0,0 +1,440 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.content.ContentValues; +import android.database.Cursor; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; +import org.getlantern.firetweet.provider.TwidereDataStore.CachedUsers; +import org.getlantern.firetweet.provider.TwidereDataStore.DirectMessages.ConversationEntries; +import org.getlantern.firetweet.util.HtmlEscapeHelper; +import org.getlantern.firetweet.util.ParseUtils; +import org.getlantern.firetweet.util.TwitterContentUtils; + +import twitter4j.URLEntity; +import twitter4j.User; + +public class ParcelableUser implements TwidereParcelable, Comparable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableUser createFromParcel(final Parcel in) { + return new ParcelableUser(in); + } + + @Override + public ParcelableUser[] newArray(final int size) { + return new ParcelableUser[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableUser createFromParcel(final JSONParcel in) { + return new ParcelableUser(in); + } + + @Override + public ParcelableUser[] newArray(final int size) { + return new ParcelableUser[size]; + } + }; + + public final long account_id, id, created_at, position; + + public final boolean is_protected, is_verified, is_follow_request_sent, is_following; + + public final String description_plain, name, screen_name, location, profile_image_url, profile_banner_url, url, + url_expanded, description_html, description_unescaped, description_expanded; + + public final int followers_count, friends_count, statuses_count, favorites_count, listed_count; + + public final int background_color, link_color, text_color; + + public final boolean is_cache, is_basic; + + public ParcelableUser(final long account_id, final long id, final String name, + final String screen_name, final String profile_image_url) { + this.account_id = account_id; + this.id = id; + this.name = name; + this.screen_name = screen_name; + this.profile_image_url = profile_image_url; + this.created_at = 0; + this.position = 0; + is_protected = false; + is_verified = false; + is_follow_request_sent = false; + is_following = false; + description_plain = null; + location = null; + profile_banner_url = null; + url = null; + url_expanded = null; + description_html = null; + description_unescaped = null; + description_expanded = null; + followers_count = 0; + friends_count = 0; + statuses_count = 0; + favorites_count = 0; + listed_count = 0; + background_color = 0; + link_color = 0; + text_color = 0; + is_cache = true; + is_basic = true; + } + + public ParcelableUser(final Cursor cursor, CachedIndices indices, final long account_id) { + this.account_id = account_id; + position = -1; + is_follow_request_sent = false; + id = indices.id != -1 ? cursor.getLong(indices.id) : -1; + name = indices.name != -1 ? cursor.getString(indices.name) : null; + screen_name = indices.screen_name != -1 ? cursor.getString(indices.screen_name) : null; + profile_image_url = indices.profile_image_url != -1 ? cursor.getString(indices.profile_image_url) : null; + created_at = indices.created_at != -1 ? cursor.getLong(indices.created_at) : -1; + is_protected = indices.is_protected != -1 && cursor.getInt(indices.is_protected) == 1; + is_verified = indices.is_verified != -1 && cursor.getInt(indices.is_verified) == 1; + favorites_count = indices.favorites_count != -1 ? cursor.getInt(indices.favorites_count) : 0; + listed_count = indices.listed_count != -1 ? cursor.getInt(indices.listed_count) : 0; + followers_count = indices.followers_count != -1 ? cursor.getInt(indices.followers_count) : 0; + friends_count = indices.friends_count != -1 ? cursor.getInt(indices.friends_count) : 0; + statuses_count = indices.statuses_count != -1 ? cursor.getInt(indices.statuses_count) : 0; + location = indices.location != -1 ? cursor.getString(indices.location) : null; + description_plain = indices.description_plain != -1 ? cursor.getString(indices.description_plain) : null; + description_html = indices.description_html != -1 ? cursor.getString(indices.description_html) : null; + description_expanded = indices.description_expanded != -1 ? cursor.getString(indices.description_expanded) : null; + url = indices.url != -1 ? cursor.getString(indices.url) : null; + url_expanded = indices.url_expanded != -1 ? cursor.getString(indices.url_expanded) : null; + profile_banner_url = indices.profile_banner_url != -1 ? cursor.getString(indices.profile_banner_url) : null; + description_unescaped = HtmlEscapeHelper.toPlainText(description_html); + is_following = indices.is_following != -1 && cursor.getInt(indices.is_following) == 1; + background_color = indices.background_color != -1 ? cursor.getInt(indices.background_color) : 0; + link_color = indices.link_color != -1 ? cursor.getInt(indices.link_color) : 0; + text_color = indices.text_color != -1 ? cursor.getInt(indices.text_color) : 0; + is_cache = true; + is_basic = indices.description_plain == -1 || indices.url == -1 || indices.location == -1; + } + + public ParcelableUser(final JSONParcel in) { + position = in.readLong("position"); + account_id = in.readLong("account_id"); + id = in.readLong("user_id"); + created_at = in.readLong("created_at"); + is_protected = in.readBoolean("is_protected"); + is_verified = in.readBoolean("is_verified"); + name = in.readString("name"); + screen_name = in.readString("screen_name"); + description_plain = in.readString("description_plain"); + description_html = in.readString("description_html"); + description_expanded = in.readString("description_expanded"); + description_unescaped = in.readString("description_unescaped"); + location = in.readString("location"); + profile_image_url = in.readString("profile_image_url"); + profile_banner_url = in.readString("profile_banner_url"); + url = in.readString("url"); + is_follow_request_sent = in.readBoolean("is_follow_request_sent"); + followers_count = in.readInt("followers_count"); + friends_count = in.readInt("friends_count"); + statuses_count = in.readInt("statuses_count"); + favorites_count = in.readInt("favorites_count"); + listed_count = in.readInt("listed_count"); + url_expanded = in.readString("url_expanded"); + is_following = in.readBoolean("is_following"); + background_color = in.readInt("background_color"); + link_color = in.readInt("link_color"); + text_color = in.readInt("text_color"); + is_cache = in.readBoolean("is_cache"); + is_basic = in.readBoolean("is_basic"); + } + + public ParcelableUser(final Parcel in) { + position = in.readLong(); + account_id = in.readLong(); + id = in.readLong(); + created_at = in.readLong(); + is_protected = in.readInt() == 1; + is_verified = in.readInt() == 1; + name = in.readString(); + screen_name = in.readString(); + description_plain = in.readString(); + description_html = in.readString(); + description_expanded = in.readString(); + description_unescaped = in.readString(); + location = in.readString(); + profile_image_url = in.readString(); + profile_banner_url = in.readString(); + url = in.readString(); + is_follow_request_sent = in.readInt() == 1; + followers_count = in.readInt(); + friends_count = in.readInt(); + statuses_count = in.readInt(); + favorites_count = in.readInt(); + listed_count = in.readInt(); + url_expanded = in.readString(); + is_following = in.readInt() == 1; + background_color = in.readInt(); + link_color = in.readInt(); + text_color = in.readInt(); + is_cache = in.readInt() == 1; + is_basic = in.readInt() == 1; + } + + public ParcelableUser(final User user, final long account_id) { + this(user, account_id, 0); + } + + public ParcelableUser(final User user, final long account_id, final long position) { + this.position = position; + this.account_id = account_id; + final URLEntity[] urls_url_entities = user.getURLEntities(); + id = user.getId(); + created_at = user.getCreatedAt().getTime(); + is_protected = user.isProtected(); + is_verified = user.isVerified(); + name = user.getName(); + screen_name = user.getScreenName(); + description_plain = user.getDescription(); + description_html = TwitterContentUtils.formatUserDescription(user); + description_expanded = TwitterContentUtils.formatExpandedUserDescription(user); + description_unescaped = HtmlEscapeHelper.toPlainText(description_html); + location = user.getLocation(); + profile_image_url = user.getProfileImageUrlHttps(); + profile_banner_url = user.getProfileBannerImageUrl(); + url = user.getURL(); + url_expanded = url != null && urls_url_entities != null && urls_url_entities.length > 0 ? urls_url_entities[0].getExpandedURL() : null; + is_follow_request_sent = user.isFollowRequestSent(); + followers_count = user.getFollowersCount(); + friends_count = user.getFriendsCount(); + statuses_count = user.getStatusesCount(); + favorites_count = user.getFavouritesCount(); + listed_count = user.getListedCount(); + is_following = user.isFollowing(); + background_color = ParseUtils.parseColor("#" + user.getProfileBackgroundColor(), 0); + link_color = ParseUtils.parseColor("#" + user.getProfileLinkColor(), 0); + text_color = ParseUtils.parseColor("#" + user.getProfileTextColor(), 0); + is_cache = false; + is_basic = false; + } + + @Override + public int compareTo(@NonNull final ParcelableUser that) { + final long diff = position - that.position; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + + @Override + public int describeContents() { + return 0; + } + + public static ParcelableUser[] fromUsersArray(@Nullable final User[] users, long account_id) { + if (users == null) return null; + final ParcelableUser[] result = new ParcelableUser[users.length]; + for (int i = 0, j = users.length; i < j; i++) { + result[i] = new ParcelableUser(users[i], account_id); + } + return result; + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeLong(position); + out.writeLong(account_id); + out.writeLong(id); + out.writeLong(created_at); + out.writeInt(is_protected ? 1 : 0); + out.writeInt(is_verified ? 1 : 0); + out.writeString(name); + out.writeString(screen_name); + out.writeString(description_plain); + out.writeString(description_html); + out.writeString(description_expanded); + out.writeString(description_unescaped); + out.writeString(location); + out.writeString(profile_image_url); + out.writeString(profile_banner_url); + out.writeString(url); + out.writeInt(is_follow_request_sent ? 1 : 0); + out.writeInt(followers_count); + out.writeInt(friends_count); + out.writeInt(statuses_count); + out.writeInt(favorites_count); + out.writeInt(listed_count); + out.writeString(url_expanded); + out.writeInt(is_following ? 1 : 0); + out.writeInt(background_color); + out.writeInt(link_color); + out.writeInt(text_color); + out.writeInt(is_cache ? 1 : 0); + out.writeInt(is_basic ? 1 : 0); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ParcelableUser)) return false; + final ParcelableUser other = (ParcelableUser) obj; + if (account_id != other.account_id) return false; + if (id != other.id) return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (account_id ^ account_id >>> 32); + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "ParcelableUser{account_id=" + account_id + ", id=" + id + ", created_at=" + created_at + ", position=" + + position + ", is_protected=" + is_protected + ", is_verified=" + is_verified + + ", is_follow_request_sent=" + is_follow_request_sent + ", is_following=" + is_following + + ", description_plain=" + description_plain + ", name=" + name + ", screen_name=" + screen_name + + ", location=" + location + ", profile_image_url=" + profile_image_url + ", profile_banner_url=" + + profile_banner_url + ", url=" + url + ", url_expanded=" + url_expanded + ", description_html=" + + description_html + ", description_unescaped=" + description_unescaped + ", description_expanded=" + + description_expanded + ", followers_count=" + followers_count + ", friends_count=" + friends_count + + ", statuses_count=" + statuses_count + ", favorites_count=" + favorites_count + ", is_cache=" + + is_cache + "}"; + } + + public static ParcelableUser fromDirectMessageConversationEntry(final Cursor cursor) { + final long account_id = cursor.getLong(ConversationEntries.IDX_ACCOUNT_ID); + final long id = cursor.getLong(ConversationEntries.IDX_CONVERSATION_ID); + final String name = cursor.getString(ConversationEntries.IDX_NAME); + final String screen_name = cursor.getString(ConversationEntries.IDX_SCREEN_NAME); + final String profile_image_url = cursor.getString(ConversationEntries.IDX_PROFILE_IMAGE_URL); + return new ParcelableUser(account_id, id, name, screen_name, profile_image_url); + } + + public static ContentValues makeCachedUserContentValues(final ParcelableUser user) { + if (user == null) return null; + final ContentValues values = new ContentValues(); + values.put(CachedUsers.USER_ID, user.id); + values.put(CachedUsers.NAME, user.name); + values.put(CachedUsers.SCREEN_NAME, user.screen_name); + values.put(CachedUsers.PROFILE_IMAGE_URL, user.profile_image_url); + values.put(CachedUsers.CREATED_AT, user.created_at); + values.put(CachedUsers.IS_PROTECTED, user.is_protected); + values.put(CachedUsers.IS_VERIFIED, user.is_verified); + values.put(CachedUsers.LISTED_COUNT, user.listed_count); + values.put(CachedUsers.FAVORITES_COUNT, user.favorites_count); + values.put(CachedUsers.FOLLOWERS_COUNT, user.followers_count); + values.put(CachedUsers.FRIENDS_COUNT, user.friends_count); + values.put(CachedUsers.STATUSES_COUNT, user.statuses_count); + values.put(CachedUsers.LOCATION, user.location); + values.put(CachedUsers.DESCRIPTION_PLAIN, user.description_plain); + values.put(CachedUsers.DESCRIPTION_HTML, user.description_html); + values.put(CachedUsers.DESCRIPTION_EXPANDED, user.description_expanded); + values.put(CachedUsers.URL, user.url); + values.put(CachedUsers.URL_EXPANDED, user.url_expanded); + values.put(CachedUsers.PROFILE_BANNER_URL, user.profile_banner_url); + values.put(CachedUsers.IS_FOLLOWING, user.is_following); + values.put(CachedUsers.BACKGROUND_COLOR, user.background_color); + values.put(CachedUsers.LINK_COLOR, user.link_color); + values.put(CachedUsers.TEXT_COLOR, user.text_color); + return values; + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeLong("position", position); + out.writeLong("account_id", account_id); + out.writeLong("user_id", id); + out.writeLong("created_at", created_at); + out.writeBoolean("is_protected", is_protected); + out.writeBoolean("is_verified", is_verified); + out.writeString("name", name); + out.writeString("screen_name", screen_name); + out.writeString("description_plain", description_plain); + out.writeString("description_html", description_html); + out.writeString("description_expanded", description_expanded); + out.writeString("description_unescaped", description_unescaped); + out.writeString("location", location); + out.writeString("profile_image_url", profile_image_url); + out.writeString("profile_banner_url", profile_banner_url); + out.writeString("url", url); + out.writeBoolean("is_follow_request_sent", is_follow_request_sent); + out.writeInt("followers_count", followers_count); + out.writeInt("friends_count", friends_count); + out.writeInt("statuses_count", statuses_count); + out.writeInt("favorites_count", favorites_count); + out.writeInt("listed_count", listed_count); + out.writeString("url_expanded", url_expanded); + out.writeBoolean("is_following", is_following); + out.writeInt("background_color", background_color); + out.writeInt("link_color", link_color); + out.writeInt("text_color", text_color); + out.writeBoolean("is_cache", is_cache); + out.writeBoolean("is_basic", is_basic); + } + + public static final class CachedIndices { + + public final int id, name, screen_name, profile_image_url, created_at, is_protected, + is_verified, favorites_count, listed_count, followers_count, friends_count, + statuses_count, location, description_plain, description_html, description_expanded, + url, url_expanded, profile_banner_url, is_following, background_color, link_color, text_color; + + public CachedIndices(Cursor cursor) { + id = cursor.getColumnIndex(CachedUsers.USER_ID); + name = cursor.getColumnIndex(CachedUsers.NAME); + screen_name = cursor.getColumnIndex(CachedUsers.SCREEN_NAME); + profile_image_url = cursor.getColumnIndex(CachedUsers.PROFILE_IMAGE_URL); + created_at = cursor.getColumnIndex(CachedUsers.CREATED_AT); + is_protected = cursor.getColumnIndex(CachedUsers.IS_PROTECTED); + is_verified = cursor.getColumnIndex(CachedUsers.IS_VERIFIED); + favorites_count = cursor.getColumnIndex(CachedUsers.FAVORITES_COUNT); + listed_count = cursor.getColumnIndex(CachedUsers.LISTED_COUNT); + followers_count = cursor.getColumnIndex(CachedUsers.FOLLOWERS_COUNT); + friends_count = cursor.getColumnIndex(CachedUsers.FRIENDS_COUNT); + statuses_count = cursor.getColumnIndex(CachedUsers.STATUSES_COUNT); + location = cursor.getColumnIndex(CachedUsers.LOCATION); + description_plain = cursor.getColumnIndex(CachedUsers.DESCRIPTION_PLAIN); + description_html = cursor.getColumnIndex(CachedUsers.DESCRIPTION_HTML); + description_expanded = cursor.getColumnIndex(CachedUsers.DESCRIPTION_EXPANDED); + url = cursor.getColumnIndex(CachedUsers.URL); + url_expanded = cursor.getColumnIndex(CachedUsers.URL_EXPANDED); + profile_banner_url = cursor.getColumnIndex(CachedUsers.PROFILE_BANNER_URL); + is_following = cursor.getColumnIndex(CachedUsers.IS_FOLLOWING); + background_color = cursor.getColumnIndex(CachedUsers.BACKGROUND_COLOR); + link_color = cursor.getColumnIndex(CachedUsers.LINK_COLOR); + text_color = cursor.getColumnIndex(CachedUsers.TEXT_COLOR); + } + + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUserList.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUserList.java new file mode 100644 index 00000000..afb94633 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUserList.java @@ -0,0 +1,200 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; + +import twitter4j.User; +import twitter4j.UserList; + +public class ParcelableUserList implements Parcelable, JSONParcelable, Comparable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableUserList createFromParcel(final Parcel in) { + return new ParcelableUserList(in); + } + + @Override + public ParcelableUserList[] newArray(final int size) { + return new ParcelableUserList[size]; + } + }; + + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableUserList createFromParcel(final JSONParcel in) { + return new ParcelableUserList(in); + } + + @Override + public ParcelableUserList[] newArray(final int size) { + return new ParcelableUserList[size]; + } + }; + + public final int members_count, subscribers_count; + + public final long account_id, id, user_id, position; + + public final boolean is_public, is_following; + + public final String description, name, user_screen_name, user_name, user_profile_image_url; + + public ParcelableUserList(final JSONParcel in) { + position = in.readLong("position"); + account_id = in.readLong("account_id"); + id = in.readLong("list_id"); + is_public = in.readBoolean("is_public"); + is_following = in.readBoolean("is_following"); + name = in.readString("name"); + description = in.readString("description"); + user_id = in.readLong("user_id"); + user_name = in.readString("user_name"); + user_screen_name = in.readString("user_screen_name"); + user_profile_image_url = in.readString("user_profile_image_url"); + members_count = in.readInt("members_count"); + subscribers_count = in.readInt("subscribers_count"); + } + + public ParcelableUserList(final Parcel in) { + position = in.readLong(); + account_id = in.readLong(); + id = in.readLong(); + is_public = in.readInt() == 1; + is_following = in.readInt() == 1; + name = in.readString(); + description = in.readString(); + user_id = in.readLong(); + user_name = in.readString(); + user_screen_name = in.readString(); + user_profile_image_url = in.readString(); + members_count = in.readInt(); + subscribers_count = in.readInt(); + } + + public ParcelableUserList(final UserList list, final long account_id) { + this(list, account_id, 0); + } + + public ParcelableUserList(final UserList list, final long account_id, final long position) { + this(list, account_id, position, list.isFollowing()); + } + + public ParcelableUserList(final UserList list, final long account_id, final long position, + final boolean is_following) { + final User user = list.getUser(); + this.position = position; + this.account_id = account_id; + id = list.getId(); + is_public = list.isPublic(); + this.is_following = is_following; + name = list.getName(); + description = list.getDescription(); + user_id = user.getId(); + user_name = user.getName(); + user_screen_name = user.getScreenName(); + user_profile_image_url = user.getProfileImageUrlHttps(); + members_count = list.getMemberCount(); + subscribers_count = list.getSubscriberCount(); + } + + @Override + public int compareTo(@NonNull final ParcelableUserList another) { + final long diff = position - another.position; + if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE; + return (int) diff; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ParcelableUserList)) return false; + final ParcelableUserList other = (ParcelableUserList) obj; + if (account_id != other.account_id) return false; + if (id != other.id) return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (account_id ^ account_id >>> 32); + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "ParcelableUserList{members_count=" + members_count + ", subscribers_count=" + subscribers_count + + ", account_id=" + account_id + ", id=" + id + ", user_id=" + user_id + ", position=" + position + + ", is_public=" + is_public + ", is_following=" + is_following + ", description=" + description + + ", name=" + name + ", user_screen_name=" + user_screen_name + ", user_name=" + user_name + + ", user_profile_image_url=" + user_profile_image_url + "}"; + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeLong("position", position); + out.writeLong("account_id", account_id); + out.writeLong("list_id", id); + out.writeBoolean("is_public", is_public); + out.writeBoolean("is_following", is_following); + out.writeString("name", name); + out.writeString("description", description); + out.writeLong("user_id", user_id); + out.writeString("user_name", user_name); + out.writeString("user_screen_name", user_screen_name); + out.writeString("user_profile_image_url", user_profile_image_url); + out.writeInt("members_count", members_count); + out.writeInt("subscribers_count", subscribers_count); + } + + @Override + public void writeToParcel(final Parcel out, final int flags) { + out.writeLong(position); + out.writeLong(account_id); + out.writeLong(id); + out.writeInt(is_public ? 1 : 0); + out.writeInt(is_following ? 1 : 0); + out.writeString(name); + out.writeString(description); + out.writeLong(user_id); + out.writeString(user_name); + out.writeString(user_screen_name); + out.writeString(user_profile_image_url); + out.writeInt(members_count); + out.writeInt(subscribers_count); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUserMention.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUserMention.java new file mode 100644 index 00000000..ec1bff4b --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/ParcelableUserMention.java @@ -0,0 +1,208 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.model; + +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.getlantern.jsonserializer.JSONParcel; +import org.getlantern.jsonserializer.JSONParcelable; +import org.getlantern.jsonserializer.JSONSerializer; +import org.getlantern.firetweet.util.SimpleValueSerializer; +import org.getlantern.firetweet.util.SimpleValueSerializer.Reader; +import org.getlantern.firetweet.util.SimpleValueSerializer.SerializationException; +import org.getlantern.firetweet.util.SimpleValueSerializer.SimpleValueSerializable; +import org.getlantern.firetweet.util.SimpleValueSerializer.Writer; + +import twitter4j.Status; +import twitter4j.UserMentionEntity; + +public class ParcelableUserMention implements Parcelable, JSONParcelable, SimpleValueSerializable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public ParcelableUserMention createFromParcel(final Parcel in) { + return new ParcelableUserMention(in); + } + + @Override + public ParcelableUserMention[] newArray(final int size) { + return new ParcelableUserMention[size]; + } + }; + public static final JSONParcelable.Creator JSON_CREATOR = new JSONParcelable.Creator() { + @Override + public ParcelableUserMention createFromParcel(final JSONParcel in) { + return new ParcelableUserMention(in); + } + + @Override + public ParcelableUserMention[] newArray(final int size) { + return new ParcelableUserMention[size]; + } + }; + public static final SimpleValueSerializer.Creator SIMPLE_CREATOR = new SimpleValueSerializer.Creator() { + @Override + public ParcelableUserMention create(final SimpleValueSerializer.Reader reader) throws SerializationException { + return new ParcelableUserMention(reader); + } + + @Override + public ParcelableUserMention[] newArray(final int size) { + return new ParcelableUserMention[size]; + } + }; + public long id; + + public String name, screen_name; + + public ParcelableUserMention(final JSONParcel in) { + id = in.readLong("id"); + name = in.readString("name"); + screen_name = in.readString("screen_name"); + } + + public ParcelableUserMention(final Parcel in) { + id = in.readLong(); + name = in.readString(); + screen_name = in.readString(); + } + + public ParcelableUserMention(final UserMentionEntity entity) { + id = entity.getId(); + name = entity.getName(); + screen_name = entity.getScreenName(); + } + + public ParcelableUserMention(Reader reader) throws SerializationException { + while (reader.hasKeyValue()) { + switch (reader.nextKey()) { + case "id": { + id = reader.nextLong(); + break; + } + case "name": { + name = reader.nextString(); + break; + } + case "screen_name": { + screen_name = reader.nextString(); + break; + } + default: { + reader.skipValue(); + break; + } + } + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ParcelableUserMention)) return false; + final ParcelableUserMention other = (ParcelableUserMention) obj; + if (id != other.id) return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "ParcelableUserMention{id=" + id + ", name=" + name + ", screen_name=" + screen_name + "}"; + } + + @Override + public void write(Writer writer) { + writer.write("id", id); + writer.write("name", name); + writer.write("screen_name", screen_name); + } + + @Override + public void writeToParcel(final JSONParcel out) { + out.writeLong("id", id); + out.writeString("name", name); + out.writeString("screen_name", screen_name); + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeLong(id); + dest.writeString(name); + dest.writeString(screen_name); + } + + public static ParcelableUserMention[] fromJSONString(final String json) { + if (TextUtils.isEmpty(json)) return null; + try { + return JSONSerializer.createArray(JSON_CREATOR, new JSONArray(json)); + } catch (final JSONException e) { + return null; + } + } + + public static ParcelableUserMention[] fromStatus(final Status status) { + return fromUserMentionEntities(status.getUserMentionEntities()); + } + + public static ParcelableUserMention[] fromUserMentionEntities(final UserMentionEntity[] entities) { + if (entities == null) return null; + final ParcelableUserMention[] mentions = new ParcelableUserMention[entities.length]; + for (int i = 0, j = entities.length; i < j; i++) { + mentions[i] = new ParcelableUserMention(entities[i]); + } + return mentions; + } + + public static boolean hasMention(final ParcelableUserMention[] mentions, final long id) { + if (mentions == null) return false; + for (final ParcelableUserMention mention : mentions) { + if (mention.id == id) return true; + } + return false; + } + + public static boolean hasMention(final String json, final long id) { + final ParcelableUserMention[] mentions = fromJSONString(json); + if (mentions == null) return false; + for (final ParcelableUserMention mention : mentions) { + if (mention.id == id) return true; + } + return false; + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/StatusShortenResult.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/StatusShortenResult.java new file mode 100644 index 00000000..b79557d6 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/StatusShortenResult.java @@ -0,0 +1,71 @@ +package org.getlantern.firetweet.model; + +import android.os.Parcel; +import android.os.Parcelable; + +public class StatusShortenResult implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + + @Override + public StatusShortenResult createFromParcel(final Parcel source) { + return new StatusShortenResult(source); + } + + @Override + public StatusShortenResult[] newArray(final int size) { + return new StatusShortenResult[size]; + } + }; + + public final String shortened; + public final int error_code; + public final String error_message; + + public StatusShortenResult(final int errorCode, final String errorMessage) { + if (errorCode == 0) throw new IllegalArgumentException("Error code must not be 0"); + shortened = null; + error_code = errorCode; + error_message = errorMessage; + } + + public StatusShortenResult(final Parcel src) { + shortened = src.readString(); + error_code = src.readInt(); + error_message = src.readString(); + } + + public StatusShortenResult(final String shortened) { + if (shortened == null) throw new IllegalArgumentException("Shortened text must not be null"); + this.shortened = shortened; + error_code = 0; + error_message = null; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "StatusShortenResult{shortened=" + shortened + ", error_code=" + error_code + ", error_message=" + + error_message + "}"; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeString(shortened); + dest.writeInt(error_code); + dest.writeString(error_message); + } + + public static StatusShortenResult getInstance(final int errorCode, final String errorMessage) { + return new StatusShortenResult(errorCode, errorMessage); + } + + public static StatusShortenResult getInstance(final String shortened) { + return new StatusShortenResult(shortened); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/TwidereParcelable.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/TwidereParcelable.java new file mode 100644 index 00000000..60ee7c2c --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/TwidereParcelable.java @@ -0,0 +1,9 @@ +package org.getlantern.firetweet.model; + +import android.os.Parcelable; + +import org.getlantern.jsonserializer.JSONParcelable; + +public interface TwidereParcelable extends Parcelable, JSONParcelable { + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/UploaderMediaItem.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/UploaderMediaItem.java new file mode 100644 index 00000000..c3888257 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/model/UploaderMediaItem.java @@ -0,0 +1,71 @@ +package org.getlantern.firetweet.model; + +import android.content.Context; +import android.net.Uri; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; + +import java.io.File; +import java.io.FileNotFoundException; + +public class UploaderMediaItem implements Parcelable { + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + + @Override + public UploaderMediaItem createFromParcel(final Parcel source) { + return new UploaderMediaItem(source); + } + + @Override + public UploaderMediaItem[] newArray(final int size) { + return new UploaderMediaItem[size]; + } + }; + + public final String path; + public final ParcelFileDescriptor fd; + public final long size; + + public UploaderMediaItem(final Context context, final ParcelableMediaUpdate media) throws FileNotFoundException { + path = Uri.parse(media.uri).getPath(); + final File file = new File(path); + fd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); + size = file.length(); + } + + public UploaderMediaItem(final Parcel src) { + path = src.readString(); + fd = src.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + size = src.readLong(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + return "MediaUpload{path=" + path + ", fd=" + fd + ", size=" + size + "}"; + } + + @Override + public void writeToParcel(final Parcel dest, final int flags) { + dest.writeString(path); + dest.writeParcelable(fd, flags); + dest.writeLong(size); + } + + public static UploaderMediaItem[] getFromStatusUpdate(final Context context, final ParcelableStatusUpdate status) + throws FileNotFoundException { + if (status.media == null) return null; + final UploaderMediaItem[] uploaderItems = new UploaderMediaItem[status.media.length]; + for (int i = 0, j = uploaderItems.length; i < j; i++) { + uploaderItems[i] = new UploaderMediaItem(context, status.media[i]); + } + return uploaderItems; + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/provider/TwidereDataStore.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/provider/TwidereDataStore.java new file mode 100644 index 00000000..1f53098c --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/provider/TwidereDataStore.java @@ -0,0 +1,918 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.provider; + +import android.content.ContentResolver; +import android.net.Uri; +import android.provider.BaseColumns; + +@SuppressWarnings("unused") +public interface TwidereDataStore { + + String AUTHORITY = "firetweet"; + + String TYPE_PRIMARY_KEY = "INTEGER PRIMARY KEY AUTOINCREMENT"; + String TYPE_INT = "INTEGER"; + String TYPE_INT_UNIQUE = "INTEGER UNIQUE"; + String TYPE_BOOLEAN = "INTEGER(1)"; + String TYPE_BOOLEAN_DEFAULT_TRUE = "INTEGER(1) DEFAULT 1"; + String TYPE_BOOLEAN_DEFAULT_FALSE = "INTEGER(1) DEFAULT 0"; + String TYPE_TEXT = "TEXT"; + String TYPE_TEXT_NOT_NULL = "TEXT NOT NULL"; + String TYPE_TEXT_NOT_NULL_UNIQUE = "TEXT NOT NULL UNIQUE"; + + String CONTENT_PATH_NULL = "null_content"; + + String CONTENT_PATH_DATABASE_READY = "database_ready"; + + Uri BASE_CONTENT_URI = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) + .authority(AUTHORITY).build(); + + Uri CONTENT_URI_NULL = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH_NULL); + + Uri CONTENT_URI_DATABASE_READY = Uri.withAppendedPath(BASE_CONTENT_URI, + CONTENT_PATH_DATABASE_READY); + + Uri[] STATUSES_URIS = new Uri[]{Statuses.CONTENT_URI, Mentions.CONTENT_URI, + CachedStatuses.CONTENT_URI}; + Uri[] CACHE_URIS = new Uri[]{CachedUsers.CONTENT_URI, CachedStatuses.CONTENT_URI, + CachedHashtags.CONTENT_URI, CachedTrends.Local.CONTENT_URI}; + Uri[] DIRECT_MESSAGES_URIS = new Uri[]{DirectMessages.Inbox.CONTENT_URI, + DirectMessages.Outbox.CONTENT_URI}; + + public static interface Accounts extends BaseColumns { + + int AUTH_TYPE_OAUTH = 0; + int AUTH_TYPE_XAUTH = 1; + int AUTH_TYPE_BASIC = 2; + int AUTH_TYPE_TWIP_O_MODE = 3; + + String TABLE_NAME = "accounts"; + String CONTENT_PATH = TABLE_NAME; + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + /** + * Login name of the account
+ * Type: TEXT NOT NULL + */ + String SCREEN_NAME = "screen_name"; + + String NAME = "name"; + + /** + * Unique ID of the account
+ * Type: INTEGER (long) + */ + String ACCOUNT_ID = "account_id"; + + /** + * Auth type of the account.
Type: INTEGER + */ + String AUTH_TYPE = "auth_type"; + + /** + * Password of the account. (It will not stored)
+ * Type: TEXT + */ + String PASSWORD = "password"; + + String BASIC_AUTH_USERNAME = "basic_auth_username"; + + /** + * Password of the account for basic auth.
+ * Type: TEXT + */ + String BASIC_AUTH_PASSWORD = "basic_auth_password"; + + /** + * OAuth Token of the account.
+ * Type: TEXT + */ + String OAUTH_TOKEN = "oauth_token"; + + /** + * Token Secret of the account.
+ * Type: TEXT + */ + String OAUTH_TOKEN_SECRET = "oauth_token_secret"; + + String COLOR = "color"; + + /** + * Set to a non-zero integer if the account is activated.
+ * Type: INTEGER (boolean) + */ + String IS_ACTIVATED = "is_activated"; + + String CONSUMER_KEY = "consumer_key"; + + String CONSUMER_SECRET = "consumer_secret"; + + String SORT_POSITION = "sort_position"; + + /** + * User's profile image URL of the status.
+ * Type: TEXT + */ + String PROFILE_IMAGE_URL = "profile_image_url"; + + String PROFILE_BANNER_URL = "profile_banner_url"; + String API_URL_FORMAT = "api_url_format"; + String SAME_OAUTH_SIGNING_URL = "same_oauth_signing_url"; + String NO_VERSION_SUFFIX = "no_version_suffix"; + + String[] COLUMNS_NO_CREDENTIALS = {_ID, NAME, SCREEN_NAME, ACCOUNT_ID, + PROFILE_IMAGE_URL, PROFILE_BANNER_URL, COLOR, IS_ACTIVATED}; + + String[] COLUMNS = {_ID, NAME, SCREEN_NAME, ACCOUNT_ID, AUTH_TYPE, + BASIC_AUTH_USERNAME, BASIC_AUTH_PASSWORD, OAUTH_TOKEN, OAUTH_TOKEN_SECRET, CONSUMER_KEY, + CONSUMER_SECRET, API_URL_FORMAT, SAME_OAUTH_SIGNING_URL, NO_VERSION_SUFFIX, PROFILE_IMAGE_URL, PROFILE_BANNER_URL, COLOR, + IS_ACTIVATED, SORT_POSITION}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL, TYPE_TEXT_NOT_NULL, + TYPE_INT_UNIQUE, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, + TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_BOOLEAN, TYPE_INT}; + + } + + public static interface CachedHashtags extends CachedValues { + + String[] COLUMNS = {_ID, NAME}; + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT}; + + String TABLE_NAME = "cached_hashtags"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + } + + public static interface CachedImages extends BaseColumns { + String TABLE_NAME = "cached_images"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String URL = "url"; + + String PATH = "path"; + + String[] MATRIX_COLUMNS = {URL, PATH}; + + String[] COLUMNS = {_ID, URL, PATH}; + } + + public static interface CachedStatuses extends Statuses { + String TABLE_NAME = "cached_statuses"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + } + + public static interface CachedTrends extends CachedValues { + + String TIMESTAMP = "timestamp"; + + String[] COLUMNS = {_ID, NAME, TIMESTAMP}; + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT, TYPE_INT}; + + public static interface Local extends CachedTrends { + String TABLE_NAME = "local_trends"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + } + + } + + public static interface CachedUsers extends CachedValues { + + String TABLE_NAME = "cached_users"; + + String CONTENT_PATH = TABLE_NAME; + + String CONTENT_PATH_WITH_RELATIONSHIP = TABLE_NAME + "/with_relationship"; + + String CONTENT_PATH_WITH_SCORE = TABLE_NAME + "/with_score"; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + Uri CONTENT_URI_WITH_RELATIONSHIP = Uri.withAppendedPath(BASE_CONTENT_URI, + CONTENT_PATH_WITH_RELATIONSHIP); + Uri CONTENT_URI_WITH_SCORE = Uri.withAppendedPath(BASE_CONTENT_URI, + CONTENT_PATH_WITH_SCORE); + + String USER_ID = "user_id"; + + String CREATED_AT = "created_at"; + + String IS_PROTECTED = "is_protected"; + + String IS_VERIFIED = "is_verified"; + + String IS_FOLLOWING = "is_following"; + + String DESCRIPTION_PLAIN = "description_plain"; + + String DESCRIPTION_HTML = "description_html"; + + String DESCRIPTION_EXPANDED = "description_expanded"; + + String LOCATION = "location"; + + String URL = "url"; + + String URL_EXPANDED = "url_expanded"; + + String PROFILE_BANNER_URL = "profile_banner_url"; + + String FOLLOWERS_COUNT = "followers_count"; + + String FRIENDS_COUNT = "friends_count"; + + String STATUSES_COUNT = "statuses_count"; + + String FAVORITES_COUNT = "favorites_count"; + + String LISTED_COUNT = "listed_count"; + + String BACKGROUND_COLOR = "background_color"; + + String LINK_COLOR = "link_color"; + + String TEXT_COLOR = "text_color"; + + /** + * User's screen name of the status.
+ * Type: TEXT + */ + String SCREEN_NAME = "screen_name"; + + /** + * User's profile image URL of the status.
+ * Type: TEXT NOT NULL + */ + String PROFILE_IMAGE_URL = "profile_image_url"; + + String LAST_SEEN = "last_seen"; + + String[] COLUMNS = {_ID, USER_ID, CREATED_AT, NAME, SCREEN_NAME, + DESCRIPTION_PLAIN, LOCATION, URL, PROFILE_IMAGE_URL, PROFILE_BANNER_URL, IS_PROTECTED, + IS_VERIFIED, IS_FOLLOWING, FOLLOWERS_COUNT, FRIENDS_COUNT, STATUSES_COUNT, FAVORITES_COUNT, + LISTED_COUNT, DESCRIPTION_HTML, DESCRIPTION_EXPANDED, URL_EXPANDED, BACKGROUND_COLOR, + LINK_COLOR, TEXT_COLOR, LAST_SEEN}; + + String[] BASIC_COLUMNS = {_ID, USER_ID, + NAME, SCREEN_NAME, PROFILE_IMAGE_URL}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT_UNIQUE, TYPE_INT, + TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_BOOLEAN, + TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_TEXT, + TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT}; + + } + + public static interface CachedValues extends BaseColumns { + + String NAME = "name"; + } + + public static interface CacheFiles extends BaseColumns { + String TABLE_NAME = "cache_files"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String NAME = "name"; + + String PATH = "path"; + + String[] MATRIX_COLUMNS = {NAME, PATH}; + + String[] COLUMNS = {_ID, NAME, PATH}; + } + + public static interface DirectMessages extends BaseColumns { + + String TABLE_NAME = "messages"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String ACCOUNT_ID = "account_id"; + String MESSAGE_ID = "message_id"; + String MESSAGE_TIMESTAMP = "message_timestamp"; + String SENDER_ID = "sender_id"; + String RECIPIENT_ID = "recipient_id"; + String CONVERSATION_ID = "conversation_id"; + + String IS_OUTGOING = "is_outgoing"; + + String TEXT_HTML = "text_html"; + String TEXT_PLAIN = "text_plain"; + String TEXT_UNESCAPED = "text_unescaped"; + String SENDER_NAME = "sender_name"; + String RECIPIENT_NAME = "recipient_name"; + String SENDER_SCREEN_NAME = "sender_screen_name"; + String RECIPIENT_SCREEN_NAME = "recipient_screen_name"; + String SENDER_PROFILE_IMAGE_URL = "sender_profile_image_url"; + String RECIPIENT_PROFILE_IMAGE_URL = "recipient_profile_image_url"; + + String MEDIA_LIST = "media_list"; + + String[] COLUMNS = {_ID, ACCOUNT_ID, MESSAGE_ID, MESSAGE_TIMESTAMP, + SENDER_ID, RECIPIENT_ID, CONVERSATION_ID, IS_OUTGOING, TEXT_HTML, TEXT_PLAIN, TEXT_UNESCAPED, + SENDER_NAME, RECIPIENT_NAME, SENDER_SCREEN_NAME, RECIPIENT_SCREEN_NAME, SENDER_PROFILE_IMAGE_URL, + RECIPIENT_PROFILE_IMAGE_URL, MEDIA_LIST}; + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_INT, TYPE_INT, + TYPE_INT, TYPE_INT, TYPE_INT, TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, + TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT}; + + String DEFAULT_SORT_ORDER = MESSAGE_ID + " DESC"; + + public static interface Conversation extends DirectMessages { + + String DEFAULT_SORT_ORDER = MESSAGE_TIMESTAMP + " ASC"; + + String CONTENT_PATH_SEGMENT = "conversation"; + String CONTENT_PATH_SEGMENT_SCREEN_NAME = "conversation_screen_name"; + + String CONTENT_PATH = DirectMessages.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + String CONTENT_PATH_SCREEN_NAME = DirectMessages.CONTENT_PATH + "/" + + CONTENT_PATH_SEGMENT_SCREEN_NAME; + + Uri CONTENT_URI = Uri + .withAppendedPath(DirectMessages.CONTENT_URI, CONTENT_PATH_SEGMENT); + + Uri CONTENT_URI_SCREEN_NAME = Uri.withAppendedPath(DirectMessages.CONTENT_URI, + CONTENT_PATH_SEGMENT_SCREEN_NAME); + } + + public static interface ConversationEntries extends BaseColumns { + + String TABLE_NAME = "messages_conversation_entries"; + + String CONTENT_PATH_SEGMENT = "conversation_entries"; + String CONTENT_PATH = DirectMessages.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + + Uri CONTENT_URI = Uri + .withAppendedPath(DirectMessages.CONTENT_URI, CONTENT_PATH_SEGMENT); + + String MESSAGE_ID = DirectMessages.MESSAGE_ID; + String ACCOUNT_ID = DirectMessages.ACCOUNT_ID; + String IS_OUTGOING = DirectMessages.IS_OUTGOING; + String MESSAGE_TIMESTAMP = DirectMessages.MESSAGE_TIMESTAMP; + String NAME = "name"; + String SCREEN_NAME = "screen_name"; + String PROFILE_IMAGE_URL = "profile_image_url"; + String TEXT_HTML = DirectMessages.TEXT_HTML; + String CONVERSATION_ID = "conversation_id"; + + int IDX__ID = 0; + int IDX_MESSAGE_TIMESTAMP = 1; + int IDX_MESSAGE_ID = 2; + int IDX_ACCOUNT_ID = 3; + int IDX_IS_OUTGOING = 4; + int IDX_NAME = 5; + int IDX_SCREEN_NAME = 6; + int IDX_PROFILE_IMAGE_URL = 7; + int IDX_TEXT = 8; + int IDX_CONVERSATION_ID = 9; + } + + public static interface Inbox extends DirectMessages { + + String TABLE_NAME = "messages_inbox"; + + String CONTENT_PATH_SEGMENT = "inbox"; + String CONTENT_PATH = DirectMessages.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + + Uri CONTENT_URI = Uri + .withAppendedPath(DirectMessages.CONTENT_URI, CONTENT_PATH_SEGMENT); + + } + + public static interface Outbox extends DirectMessages { + + String TABLE_NAME = "messages_outbox"; + + String CONTENT_PATH_SEGMENT = "outbox"; + String CONTENT_PATH = DirectMessages.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + + Uri CONTENT_URI = Uri + .withAppendedPath(DirectMessages.CONTENT_URI, CONTENT_PATH_SEGMENT); + + } + + } + + public static interface SearchHistory extends BaseColumns { + + String TABLE_NAME = "search_history"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String QUERY = "query"; + + String RECENT_QUERY = "recent_query"; + + String[] COLUMNS = {_ID, RECENT_QUERY, QUERY}; + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_TEXT_NOT_NULL_UNIQUE}; + String DEFAULT_SORT_ORDER = RECENT_QUERY + " DESC"; + } + + public static interface DNS extends BaseColumns { + String TABLE_NAME = "dns"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String HOST = "host"; + + String ADDRESS = "address"; + + String[] MATRIX_COLUMNS = {HOST, ADDRESS}; + + String[] COLUMNS = {_ID, HOST, ADDRESS}; + } + + public static interface SavedSearches extends BaseColumns { + + String TABLE_NAME = "saved_searches"; + + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String ACCOUNT_ID = "account_id"; + String SEARCH_ID = "search_id"; + String QUERY = "query"; + String NAME = "name"; + String CREATED_AT = "created_at"; + + String[] COLUMNS = {_ID, ACCOUNT_ID, SEARCH_ID, CREATED_AT, + QUERY, NAME}; + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_INT, + TYPE_INT, TYPE_TEXT, TYPE_TEXT}; + String DEFAULT_SORT_ORDER = CREATED_AT + " DESC"; + } + + public static interface Drafts extends BaseColumns { + + int ACTION_UPDATE_STATUS = 1; + int ACTION_SEND_DIRECT_MESSAGE = 2; + int ACTION_CREATE_FRIENDSHIP = 3; + + String TABLE_NAME = "drafts"; + String CONTENT_PATH = TABLE_NAME; + String CONTENT_PATH_UNSENT = TABLE_NAME + "/unsent"; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + Uri CONTENT_URI_UNSENT = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH_UNSENT); + + /** + * Status content.
+ * Type: TEXT + */ + String TEXT = "text"; + + /** + * Account IDs of unsent status.
+ * Type: TEXT + */ + String ACCOUNT_IDS = "account_ids"; + + String LOCATION = "location"; + + String IN_REPLY_TO_STATUS_ID = "in_reply_to_status_id"; + + String MEDIA = "media"; + + String IS_POSSIBLY_SENSITIVE = "is_possibly_sensitive"; + + String TIMESTAMP = "timestamp"; + + String ACTION_TYPE = "action_type"; + + String ACTION_EXTRAS = "action_extras"; + + String[] COLUMNS = {_ID, TEXT, ACCOUNT_IDS, LOCATION, MEDIA, + IN_REPLY_TO_STATUS_ID, IS_POSSIBLY_SENSITIVE, TIMESTAMP, ACTION_TYPE, ACTION_EXTRAS}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, + TYPE_INT, TYPE_INT, TYPE_BOOLEAN, TYPE_INT, TYPE_INT, TYPE_TEXT}; + + } + + public static interface Filters extends BaseColumns { + + String CONTENT_PATH = "filters"; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String VALUE = "value"; + + String ENABLE_IN_HOME_TIMELINE = "enable_in_home_timeline"; + + String ENABLE_IN_MENTIONS = "enable_in_mentions"; + + String ENABLE_FOR_RETWEETS = "enable_for_retweets"; + + String[] COLUMNS = {_ID, VALUE}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL_UNIQUE}; + + public static interface Keywords extends Filters { + + String TABLE_NAME = "filtered_keywords"; + String CONTENT_PATH_SEGMENT = "keywords"; + String CONTENT_PATH = Filters.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + Uri CONTENT_URI = Uri.withAppendedPath(Filters.CONTENT_URI, CONTENT_PATH_SEGMENT); + } + + public static interface Links extends Filters { + + String TABLE_NAME = "filtered_links"; + String CONTENT_PATH_SEGMENT = "links"; + String CONTENT_PATH = Filters.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + Uri CONTENT_URI = Uri.withAppendedPath(Filters.CONTENT_URI, CONTENT_PATH_SEGMENT); + } + + public static interface Sources extends Filters { + + String TABLE_NAME = "filtered_sources"; + String CONTENT_PATH_SEGMENT = "sources"; + String CONTENT_PATH = Filters.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + Uri CONTENT_URI = Uri.withAppendedPath(Filters.CONTENT_URI, CONTENT_PATH_SEGMENT); + } + + public static interface Users extends BaseColumns { + + String TABLE_NAME = "filtered_users"; + String CONTENT_PATH_SEGMENT = "users"; + String CONTENT_PATH = Filters.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + Uri CONTENT_URI = Uri.withAppendedPath(Filters.CONTENT_URI, CONTENT_PATH_SEGMENT); + + String USER_ID = "user_id"; + String NAME = "name"; + String SCREEN_NAME = "screen_name"; + + String[] COLUMNS = {_ID, USER_ID, NAME, SCREEN_NAME}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT_UNIQUE, TYPE_TEXT_NOT_NULL, + TYPE_TEXT_NOT_NULL}; + } + } + + public static interface Mentions extends Statuses { + + String TABLE_NAME = "mentions"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + } + + public static interface Notifications extends BaseColumns { + + String TABLE_NAME = "notifications"; + + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String ID = "id"; + + String COUNT = "count"; + + String[] MATRIX_COLUMNS = {ID, COUNT}; + + String[] COLUMNS = {_ID, ID, COUNT}; + } + + public static interface Permissions extends BaseColumns { + String TABLE_NAME = "permissions"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String PERMISSION = "permissions"; + + String PACKAGE_NAME = "package_name"; + + String[] MATRIX_COLUMNS = {PACKAGE_NAME, PERMISSION}; + + String[] COLUMNS = {_ID, PACKAGE_NAME, PERMISSION}; + } + + public static interface Preferences extends BaseColumns { + String TABLE_NAME = "preferences"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + int TYPE_INVALID = -1; + + int TYPE_NULL = 0; + + int TYPE_BOOLEAN = 1; + + int TYPE_INTEGER = 2; + + int TYPE_LONG = 3; + + int TYPE_FLOAT = 4; + + int TYPE_STRING = 5; + + String KEY = "key"; + + String VALUE = "value"; + + String TYPE = "type"; + + String[] MATRIX_COLUMNS = {KEY, VALUE, TYPE}; + + String[] COLUMNS = {_ID, KEY, VALUE, TYPE}; + } + + public static interface Statuses extends BaseColumns { + + String TABLE_NAME = "statuses"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + /** + * Account ID of the status.
+ * Type: TEXT + */ + String ACCOUNT_ID = "account_id"; + + /** + * Status content, in HTML. Please note, this is not actually original + * text.
+ * Type: TEXT + */ + String TEXT_HTML = "text_html"; + + /** + * + */ + String TEXT_PLAIN = "text_plain"; + + String TEXT_UNESCAPED = "text_unescaped"; + + /** + * User name of the status.
+ * Type: TEXT + */ + String USER_NAME = "name"; + + /** + * User's screen name of the status.
+ * Type: TEXT + */ + String USER_SCREEN_NAME = "screen_name"; + + /** + * User's profile image URL of the status.
+ * Type: TEXT NOT NULL + */ + String USER_PROFILE_IMAGE_URL = "profile_image_url"; + + /** + * Unique id of the status.
+ * Type: INTEGER UNIQUE(long) + */ + String STATUS_ID = "status_id"; + + /** + * Retweet count of the status.
+ * Type: INTEGER (long) + */ + String RETWEET_COUNT = "retweet_count"; + String FAVORITE_COUNT = "favorite_count"; + String REPLY_COUNT = "reply_count"; + String DESCENDENT_REPLY_COUNT = "descendent_reply_count"; + + /** + * Set to an non-zero integer if the status is a retweet, set to + * negative value if the status is retweeted by user.
+ * Type: INTEGER + */ + String IS_RETWEET = "is_retweet"; + + String IS_QUOTE = "is_quote"; + + /** + * Set to 1 if the status is a favorite.
+ * Type: INTEGER (boolean) + */ + String IS_FAVORITE = "is_favorite"; + + String IS_POSSIBLY_SENSITIVE = "is_possibly_sensitive"; + + /** + * Set to 1 if the status is a gap.
+ * Type: INTEGER (boolean) + */ + String IS_GAP = "is_gap"; + + String LOCATION = "location"; + + String PLACE_FULL_NAME = "place_full_name"; + + /** + * User's ID of the status.
+ * Type: INTEGER (long) + */ + String USER_ID = "user_id"; + + String IN_REPLY_TO_STATUS_ID = "in_reply_to_status_id"; + + String IN_REPLY_TO_USER_ID = "in_reply_to_user_id"; + + String IN_REPLY_TO_USER_NAME = "in_reply_to_user_name"; + + String IN_REPLY_TO_USER_SCREEN_NAME = "in_reply_to_user_screen_name"; + + String SOURCE = "source"; + + String IS_PROTECTED = "is_protected"; + + String IS_VERIFIED = "is_verified"; + + String IS_FOLLOWING = "is_following"; + + String RETWEET_ID = "retweet_id"; + + String RETWEET_TIMESTAMP = "retweet_timestamp"; + + String RETWEETED_BY_USER_ID = "retweeted_by_user_id"; + + String RETWEETED_BY_USER_NAME = "retweeted_by_user_name"; + + String RETWEETED_BY_USER_SCREEN_NAME = "retweeted_by_user_screen_name"; + + String RETWEETED_BY_USER_PROFILE_IMAGE = "retweeted_by_user_profile_image"; + + /** + * Timestamp of the status.
+ * Type: INTEGER (long) + */ + String STATUS_TIMESTAMP = "status_timestamp"; + + String MY_RETWEET_ID = "my_retweet_id"; + + String MY_QUOTE_ID = "my_quote_id"; + + String MEDIA_LIST = "media_list"; + + String MENTIONS_LIST = "mentions_list"; + + String CARD = "card"; + + String CARD_NAME = "card_type"; + + String SORT_ORDER_TIMESTAMP_DESC = STATUS_TIMESTAMP + " DESC"; + + String SORT_ORDER_STATUS_ID_DESC = STATUS_ID + " DESC"; + + String DEFAULT_SORT_ORDER = SORT_ORDER_TIMESTAMP_DESC; + + String QUOTE_ID = "quote_id"; + String QUOTE_TEXT_HTML = "quote_text_html"; + String QUOTE_TEXT_PLAIN = "quote_text_plain"; + String QUOTE_TEXT_UNESCAPED = "quote_text_unescaped"; + String QUOTE_TIMESTAMP = "quote_timestamp"; + String QUOTE_SOURCE = "quote_source"; + String QUOTED_BY_USER_ID = "quoted_by_user_id"; + String QUOTED_BY_USER_NAME = "quoted_by_user_name"; + String QUOTED_BY_USER_SCREEN_NAME = "quoted_by_user_screen_name"; + String QUOTED_BY_USER_PROFILE_IMAGE = "quoted_by_user_profile_image"; + String QUOTED_BY_USER_IS_VERIFIED = "quoted_by_user_is_verified"; + String QUOTED_BY_USER_IS_PROTECTED = "quoted_by_user_is_protected"; + + String[] COLUMNS = {_ID, ACCOUNT_ID, STATUS_ID, USER_ID, + STATUS_TIMESTAMP, TEXT_HTML, TEXT_PLAIN, TEXT_UNESCAPED, USER_NAME, USER_SCREEN_NAME, + USER_PROFILE_IMAGE_URL, IN_REPLY_TO_STATUS_ID, IN_REPLY_TO_USER_ID, IN_REPLY_TO_USER_NAME, + IN_REPLY_TO_USER_SCREEN_NAME, SOURCE, LOCATION, RETWEET_COUNT, FAVORITE_COUNT, REPLY_COUNT, + DESCENDENT_REPLY_COUNT, RETWEET_ID, RETWEET_TIMESTAMP, RETWEETED_BY_USER_ID, + RETWEETED_BY_USER_NAME, RETWEETED_BY_USER_SCREEN_NAME, RETWEETED_BY_USER_PROFILE_IMAGE, + QUOTE_ID, QUOTE_TEXT_HTML, QUOTE_TEXT_PLAIN, QUOTE_TEXT_UNESCAPED, QUOTE_TIMESTAMP, + QUOTE_SOURCE, QUOTED_BY_USER_ID, QUOTED_BY_USER_NAME, QUOTED_BY_USER_SCREEN_NAME, + QUOTED_BY_USER_PROFILE_IMAGE, QUOTED_BY_USER_IS_VERIFIED, QUOTED_BY_USER_IS_PROTECTED, + MY_RETWEET_ID, IS_RETWEET, IS_QUOTE, IS_FAVORITE, IS_PROTECTED, IS_VERIFIED, IS_FOLLOWING, + IS_GAP, IS_POSSIBLY_SENSITIVE, MEDIA_LIST, MENTIONS_LIST, CARD_NAME, CARD, PLACE_FULL_NAME}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_INT, + TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, + TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_INT, + TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, + TYPE_TEXT, TYPE_INT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_INT, TYPE_TEXT, TYPE_INT, + TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_INT, TYPE_BOOLEAN, + TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_BOOLEAN, + TYPE_BOOLEAN, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT, TYPE_TEXT}; + + } + + public static interface Tabs extends BaseColumns { + String TABLE_NAME = "tabs"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String NAME = "name"; + + String ICON = "icon"; + + String TYPE = "type"; + + String ARGUMENTS = "arguments"; + + String EXTRAS = "extras"; + + String POSITION = "position"; + + String[] COLUMNS = {_ID, NAME, ICON, TYPE, ARGUMENTS, EXTRAS, + POSITION}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_TEXT, TYPE_TEXT, + TYPE_TEXT_NOT_NULL, TYPE_TEXT, TYPE_TEXT, TYPE_INT}; + + String DEFAULT_SORT_ORDER = POSITION + " ASC"; + } + + public static interface CachedRelationships extends BaseColumns { + + String TABLE_NAME = "cached_relationships"; + String CONTENT_PATH = TABLE_NAME; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String ACCOUNT_ID = "account_id"; + + String USER_ID = "user_id"; + + String FOLLOWING = "following"; + + String FOLLOWED_BY = "followed_by"; + + String BLOCKING = "blocking"; + + String BLOCKED_BY = "blocked_by"; + + String MUTING = "muting"; + + String[] COLUMNS = {_ID, ACCOUNT_ID, USER_ID, FOLLOWING, FOLLOWED_BY, BLOCKING, + BLOCKED_BY, MUTING}; + + String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_INT, TYPE_BOOLEAN_DEFAULT_FALSE, + TYPE_BOOLEAN_DEFAULT_FALSE, TYPE_BOOLEAN_DEFAULT_FALSE, TYPE_BOOLEAN_DEFAULT_FALSE, + TYPE_BOOLEAN_DEFAULT_FALSE}; + } + + public static interface UnreadCounts extends BaseColumns { + + String CONTENT_PATH = "unread_counts"; + + Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH); + + String TAB_POSITION = "tab_position"; + + String TAB_TYPE = "tab_type"; + + String COUNT = "count"; + + String[] MATRIX_COLUMNS = {TAB_POSITION, TAB_TYPE, COUNT}; + + String[] COLUMNS = {_ID, TAB_POSITION, TAB_TYPE, COUNT}; + + public static interface ByType extends UnreadCounts { + + String CONTENT_PATH_SEGMENT = "by_type"; + + String CONTENT_PATH = UnreadCounts.CONTENT_PATH + "/" + CONTENT_PATH_SEGMENT; + + Uri CONTENT_URI = Uri.withAppendedPath(UnreadCounts.CONTENT_URI, CONTENT_PATH_SEGMENT); + } + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/ContentValuesCreator.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/ContentValuesCreator.java new file mode 100644 index 00000000..dfb81538 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/ContentValuesCreator.java @@ -0,0 +1,442 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import android.content.ContentValues; + +import org.json.JSONException; +import org.json.JSONObject; +import org.getlantern.jsonserializer.JSONSerializer; +import org.getlantern.firetweet.TwidereConstants; +import org.getlantern.firetweet.model.ParcelableAccount; +import org.getlantern.firetweet.model.ParcelableDirectMessage; +import org.getlantern.firetweet.model.ParcelableLocation; +import org.getlantern.firetweet.model.ParcelableMedia; +import org.getlantern.firetweet.model.ParcelableMediaUpdate; +import org.getlantern.firetweet.model.ParcelableStatus; +import org.getlantern.firetweet.model.ParcelableStatus.ParcelableCardEntity; +import org.getlantern.firetweet.model.ParcelableStatusUpdate; +import org.getlantern.firetweet.model.ParcelableUser; +import org.getlantern.firetweet.model.ParcelableUserMention; +import org.getlantern.firetweet.provider.TwidereDataStore.Accounts; +import org.getlantern.firetweet.provider.TwidereDataStore.CachedRelationships; +import org.getlantern.firetweet.provider.TwidereDataStore.CachedTrends; +import org.getlantern.firetweet.provider.TwidereDataStore.CachedUsers; +import org.getlantern.firetweet.provider.TwidereDataStore.DirectMessages; +import org.getlantern.firetweet.provider.TwidereDataStore.Drafts; +import org.getlantern.firetweet.provider.TwidereDataStore.Filters; +import org.getlantern.firetweet.provider.TwidereDataStore.SavedSearches; +import org.getlantern.firetweet.provider.TwidereDataStore.Statuses; + +import java.util.ArrayList; +import java.util.List; + +import twitter4j.DirectMessage; +import twitter4j.GeoLocation; +import twitter4j.Place; +import twitter4j.Relationship; +import twitter4j.SavedSearch; +import twitter4j.Status; +import twitter4j.Trend; +import twitter4j.Trends; +import twitter4j.URLEntity; +import twitter4j.User; +import twitter4j.auth.AccessToken; +import twitter4j.conf.Configuration; + +import static org.getlantern.firetweet.util.HtmlEscapeHelper.toPlainText; + +public final class ContentValuesCreator implements TwidereConstants { + + public static ContentValues createAccount(final Configuration conf, final String basicUsername, + final String basicPassword, final User user, + final int color, final String apiUrlFormat, + final boolean noVersionSuffix) { + if (user == null || user.getId() <= 0) return null; + final ContentValues values = new ContentValues(); + if (basicUsername == null || basicPassword == null) return null; + values.put(Accounts.BASIC_AUTH_USERNAME, basicUsername); + values.put(Accounts.BASIC_AUTH_PASSWORD, basicPassword); + values.put(Accounts.AUTH_TYPE, Accounts.AUTH_TYPE_BASIC); + values.put(Accounts.ACCOUNT_ID, user.getId()); + values.put(Accounts.SCREEN_NAME, user.getScreenName()); + values.put(Accounts.NAME, user.getName()); + values.put(Accounts.PROFILE_IMAGE_URL, user.getProfileImageUrlHttps()); + values.put(Accounts.PROFILE_BANNER_URL, user.getProfileBannerImageUrl()); + values.put(Accounts.COLOR, color); + values.put(Accounts.IS_ACTIVATED, 1); + values.put(Accounts.API_URL_FORMAT, apiUrlFormat); + values.put(Accounts.NO_VERSION_SUFFIX, noVersionSuffix); + return values; + } + + public static ContentValues createAccount(final Configuration conf, final AccessToken accessToken, + final User user, final int authType, final int color, + final String apiUrlFormat, final boolean sameOAuthSigningUrl, + final boolean noVersionSuffix) { + if (user == null || user.getId() <= 0 || accessToken == null || user.getId() != accessToken.getUserId()) + return null; + final ContentValues values = new ContentValues(); + values.put(Accounts.OAUTH_TOKEN, accessToken.getToken()); + values.put(Accounts.OAUTH_TOKEN_SECRET, accessToken.getTokenSecret()); + values.put(Accounts.CONSUMER_KEY, conf.getOAuthConsumerKey()); + values.put(Accounts.CONSUMER_SECRET, conf.getOAuthConsumerSecret()); + values.put(Accounts.AUTH_TYPE, authType); + values.put(Accounts.ACCOUNT_ID, user.getId()); + values.put(Accounts.SCREEN_NAME, user.getScreenName()); + values.put(Accounts.NAME, user.getName()); + values.put(Accounts.PROFILE_IMAGE_URL, user.getProfileImageUrlHttps()); + values.put(Accounts.PROFILE_BANNER_URL, user.getProfileBannerImageUrl()); + values.put(Accounts.COLOR, color); + values.put(Accounts.IS_ACTIVATED, 1); + values.put(Accounts.API_URL_FORMAT, apiUrlFormat); + values.put(Accounts.SAME_OAUTH_SIGNING_URL, sameOAuthSigningUrl); + values.put(Accounts.NO_VERSION_SUFFIX, noVersionSuffix); + return values; + } + + public static ContentValues createAccount(final Configuration conf, final User user, final int color, + final String apiUrlFormat, final boolean noVersionSuffix) { + if (user == null || user.getId() <= 0) return null; + final ContentValues values = new ContentValues(); + values.put(Accounts.AUTH_TYPE, Accounts.AUTH_TYPE_TWIP_O_MODE); + values.put(Accounts.ACCOUNT_ID, user.getId()); + values.put(Accounts.SCREEN_NAME, user.getScreenName()); + values.put(Accounts.NAME, user.getName()); + values.put(Accounts.PROFILE_IMAGE_URL, (user.getProfileImageUrlHttps())); + values.put(Accounts.PROFILE_BANNER_URL, (user.getProfileBannerImageUrl())); + values.put(Accounts.COLOR, color); + values.put(Accounts.IS_ACTIVATED, 1); + values.put(Accounts.API_URL_FORMAT, apiUrlFormat); + values.put(Accounts.NO_VERSION_SUFFIX, noVersionSuffix); + return values; + } + + public static ContentValues createCachedRelationship(final Relationship relationship, + final long accountId) { + final ContentValues values = new ContentValues(); + values.put(CachedRelationships.ACCOUNT_ID, accountId); + values.put(CachedRelationships.USER_ID, relationship.getTargetUserId()); + values.put(CachedRelationships.FOLLOWING, relationship.isSourceFollowingTarget()); + values.put(CachedRelationships.FOLLOWED_BY, relationship.isSourceFollowedByTarget()); + values.put(CachedRelationships.BLOCKING, relationship.isSourceBlockingTarget()); + values.put(CachedRelationships.BLOCKED_BY, relationship.isSourceBlockedByTarget()); + values.put(CachedRelationships.MUTING, relationship.isSourceMutingTarget()); + return values; + } + + public static ContentValues createCachedUser(final User user) { + if (user == null || user.getId() <= 0) return null; + final String profile_image_url = user.getProfileImageUrlHttps(); + final String url = user.getURL(); + final URLEntity[] urls = user.getURLEntities(); + final ContentValues values = new ContentValues(); + values.put(CachedUsers.USER_ID, user.getId()); + values.put(CachedUsers.NAME, user.getName()); + values.put(CachedUsers.SCREEN_NAME, user.getScreenName()); + values.put(CachedUsers.PROFILE_IMAGE_URL, profile_image_url); + values.put(CachedUsers.PROFILE_BANNER_URL, user.getProfileBannerImageUrl()); + values.put(CachedUsers.CREATED_AT, user.getCreatedAt().getTime()); + values.put(CachedUsers.IS_PROTECTED, user.isProtected()); + values.put(CachedUsers.IS_VERIFIED, user.isVerified()); + values.put(CachedUsers.IS_FOLLOWING, user.isFollowing()); + values.put(CachedUsers.FAVORITES_COUNT, user.getFavouritesCount()); + values.put(CachedUsers.FOLLOWERS_COUNT, user.getFollowersCount()); + values.put(CachedUsers.FRIENDS_COUNT, user.getFriendsCount()); + values.put(CachedUsers.STATUSES_COUNT, user.getStatusesCount()); + values.put(CachedUsers.LISTED_COUNT, user.getListedCount()); + values.put(CachedUsers.LOCATION, user.getLocation()); + values.put(CachedUsers.DESCRIPTION_PLAIN, user.getDescription()); + values.put(CachedUsers.DESCRIPTION_HTML, TwitterContentUtils.formatUserDescription(user)); + values.put(CachedUsers.DESCRIPTION_EXPANDED, TwitterContentUtils.formatExpandedUserDescription(user)); + values.put(CachedUsers.URL, url); + if (url != null && urls != null && urls.length > 0) { + values.put(CachedUsers.URL_EXPANDED, urls[0].getExpandedURL()); + } + values.put(CachedUsers.BACKGROUND_COLOR, ParseUtils.parseColor("#" + user.getProfileBackgroundColor(), 0)); + values.put(CachedUsers.LINK_COLOR, ParseUtils.parseColor("#" + user.getProfileLinkColor(), 0)); + values.put(CachedUsers.TEXT_COLOR, ParseUtils.parseColor("#" + user.getProfileTextColor(), 0)); + return values; + } + + public static ContentValues createDirectMessage(final DirectMessage message, final long accountId, + final boolean isOutgoing) { + if (message == null) return null; + final ContentValues values = new ContentValues(); + final User sender = message.getSender(), recipient = message.getRecipient(); + if (sender == null || recipient == null) return null; + final String sender_profile_image_url = sender.getProfileImageUrlHttps(); + final String recipient_profile_image_url = recipient.getProfileImageUrlHttps(); + values.put(DirectMessages.ACCOUNT_ID, accountId); + values.put(DirectMessages.MESSAGE_ID, message.getId()); + values.put(DirectMessages.MESSAGE_TIMESTAMP, message.getCreatedAt().getTime()); + values.put(DirectMessages.SENDER_ID, sender.getId()); + values.put(DirectMessages.RECIPIENT_ID, recipient.getId()); + if (isOutgoing) { + values.put(DirectMessages.CONVERSATION_ID, recipient.getId()); + } else { + values.put(DirectMessages.CONVERSATION_ID, sender.getId()); + } + final String text_html = TwitterContentUtils.formatDirectMessageText(message); + values.put(DirectMessages.TEXT_HTML, text_html); + values.put(DirectMessages.TEXT_PLAIN, message.getText()); + values.put(DirectMessages.TEXT_UNESCAPED, toPlainText(text_html)); + values.put(DirectMessages.IS_OUTGOING, isOutgoing); + values.put(DirectMessages.SENDER_NAME, sender.getName()); + values.put(DirectMessages.SENDER_SCREEN_NAME, sender.getScreenName()); + values.put(DirectMessages.RECIPIENT_NAME, recipient.getName()); + values.put(DirectMessages.RECIPIENT_SCREEN_NAME, recipient.getScreenName()); + values.put(DirectMessages.SENDER_PROFILE_IMAGE_URL, sender_profile_image_url); + values.put(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL, recipient_profile_image_url); + final ParcelableMedia[] mediaArray = ParcelableMedia.fromEntities(message); + if (mediaArray != null) { + values.put(DirectMessages.MEDIA_LIST, SimpleValueSerializer.toSerializedString(mediaArray)); + } + return values; + } + + public static ContentValues createDirectMessage(final ParcelableDirectMessage message) { + if (message == null) return null; + final ContentValues values = new ContentValues(); + values.put(DirectMessages.ACCOUNT_ID, message.account_id); + values.put(DirectMessages.MESSAGE_ID, message.id); + values.put(DirectMessages.MESSAGE_TIMESTAMP, message.timestamp); + values.put(DirectMessages.SENDER_ID, message.sender_id); + values.put(DirectMessages.RECIPIENT_ID, message.recipient_id); + values.put(DirectMessages.TEXT_HTML, message.text_html); + values.put(DirectMessages.TEXT_PLAIN, message.text_plain); + values.put(DirectMessages.IS_OUTGOING, message.is_outgoing); + values.put(DirectMessages.SENDER_NAME, message.sender_name); + values.put(DirectMessages.SENDER_SCREEN_NAME, message.sender_screen_name); + values.put(DirectMessages.RECIPIENT_NAME, message.recipient_name); + values.put(DirectMessages.RECIPIENT_SCREEN_NAME, message.recipient_screen_name); + values.put(DirectMessages.SENDER_PROFILE_IMAGE_URL, message.sender_profile_image_url); + values.put(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL, message.recipient_profile_image_url); + if (message.media != null) { + values.put(Statuses.MEDIA_LIST, SimpleValueSerializer.toSerializedString(message.media)); + } + return values; + } + + public static ContentValues createFilteredUser(final ParcelableStatus status) { + if (status == null) return null; + final ContentValues values = new ContentValues(); + values.put(Filters.Users.USER_ID, status.user_id); + values.put(Filters.Users.NAME, status.user_name); + values.put(Filters.Users.SCREEN_NAME, status.user_screen_name); + return values; + } + + public static ContentValues createFilteredUser(final ParcelableUser user) { + if (user == null) return null; + final ContentValues values = new ContentValues(); + values.put(Filters.Users.USER_ID, user.id); + values.put(Filters.Users.NAME, user.name); + values.put(Filters.Users.SCREEN_NAME, user.screen_name); + return values; + } + + public static ContentValues createFilteredUser(final ParcelableUserMention user) { + if (user == null) return null; + final ContentValues values = new ContentValues(); + values.put(Filters.Users.USER_ID, user.id); + values.put(Filters.Users.NAME, user.name); + values.put(Filters.Users.SCREEN_NAME, user.screen_name); + return values; + } + + public static ContentValues createMessageDraft(final long accountId, final long recipientId, + final String text, final String imageUri) { + final ContentValues values = new ContentValues(); + values.put(Drafts.ACTION_TYPE, Drafts.ACTION_SEND_DIRECT_MESSAGE); + values.put(Drafts.TEXT, text); + values.put(Drafts.ACCOUNT_IDS, TwidereArrayUtils.toString(new long[]{accountId}, ',', false)); + values.put(Drafts.TIMESTAMP, System.currentTimeMillis()); + if (imageUri != null) { + final ParcelableMediaUpdate[] mediaArray = {new ParcelableMediaUpdate(imageUri, 0)}; + values.put(Drafts.MEDIA, JSONSerializer.toJSONArrayString(mediaArray)); + } + final JSONObject extras = new JSONObject(); + try { + extras.put(EXTRA_RECIPIENT_ID, recipientId); + } catch (final JSONException e) { + e.printStackTrace(); + } + values.put(Drafts.ACTION_EXTRAS, extras.toString()); + return values; + } + + public static ContentValues createSavedSearch(final SavedSearch savedSearch, final long accountId) { + final ContentValues values = new ContentValues(); + values.put(SavedSearches.ACCOUNT_ID, accountId); + values.put(SavedSearches.SEARCH_ID, savedSearch.getId()); + values.put(SavedSearches.CREATED_AT, savedSearch.getCreatedAt().getTime()); + values.put(SavedSearches.NAME, savedSearch.getName()); + values.put(SavedSearches.QUERY, savedSearch.getQuery()); + return values; + } + + public static ContentValues[] createSavedSearches(final List savedSearches, long accountId) { + final ContentValues[] resultValuesArray = new ContentValues[savedSearches.size()]; + for (int i = 0, j = savedSearches.size(); i < j; i++) { + resultValuesArray[i] = createSavedSearch(savedSearches.get(i), accountId); + } + return resultValuesArray; + } + + public static ContentValues createStatus(final Status orig, final long accountId) { + if (orig == null || orig.getId() <= 0) return null; + final ContentValues values = new ContentValues(); + values.put(Statuses.ACCOUNT_ID, accountId); + values.put(Statuses.STATUS_ID, orig.getId()); + values.put(Statuses.STATUS_TIMESTAMP, orig.getCreatedAt().getTime()); + final Status status; + if (orig.isRetweet()) { + final Status retweetedStatus = orig.getRetweetedStatus(); + final User retweetUser = orig.getUser(); + final long retweetedById = retweetUser.getId(); + values.put(Statuses.RETWEET_ID, retweetedStatus.getId()); + values.put(Statuses.RETWEET_TIMESTAMP, retweetedStatus.getCreatedAt().getTime()); + values.put(Statuses.RETWEETED_BY_USER_ID, retweetedById); + values.put(Statuses.RETWEETED_BY_USER_NAME, retweetUser.getName()); + values.put(Statuses.RETWEETED_BY_USER_SCREEN_NAME, retweetUser.getScreenName()); + values.put(Statuses.RETWEETED_BY_USER_PROFILE_IMAGE, (retweetUser.getProfileImageUrlHttps())); + values.put(Statuses.IS_RETWEET, true); + if (retweetedById == accountId) { + values.put(Statuses.MY_RETWEET_ID, orig.getId()); + } else { + values.put(Statuses.MY_RETWEET_ID, orig.getCurrentUserRetweet()); + } + status = retweetedStatus; + } else if (orig.isQuote()) { + final Status quotedStatus = orig.getQuotedStatus(); + final User quoteUser = orig.getUser(); + final long quotedById = quoteUser.getId(); + values.put(Statuses.QUOTE_ID, quotedStatus.getId()); + final String textHtml = TwitterContentUtils.formatStatusText(orig); + values.put(Statuses.QUOTE_TEXT_HTML, textHtml); + values.put(Statuses.QUOTE_TEXT_PLAIN, orig.getText()); + values.put(Statuses.QUOTE_TEXT_UNESCAPED, toPlainText(textHtml)); + values.put(Statuses.QUOTE_TIMESTAMP, orig.getCreatedAt().getTime()); + values.put(Statuses.QUOTE_SOURCE, orig.getSource()); + + values.put(Statuses.QUOTED_BY_USER_ID, quotedById); + values.put(Statuses.QUOTED_BY_USER_NAME, quoteUser.getName()); + values.put(Statuses.QUOTED_BY_USER_SCREEN_NAME, quoteUser.getScreenName()); + values.put(Statuses.QUOTED_BY_USER_PROFILE_IMAGE, quoteUser.getProfileImageUrlHttps()); + values.put(Statuses.QUOTED_BY_USER_IS_VERIFIED, quoteUser.isVerified()); + values.put(Statuses.QUOTED_BY_USER_IS_PROTECTED, quoteUser.isProtected()); + values.put(Statuses.IS_QUOTE, true); + if (quotedById == accountId) { + values.put(Statuses.MY_QUOTE_ID, orig.getId()); +// } else { +// values.put(Statuses.MY_QUOTE_ID, orig.getCurrentUserRetweet()); + } + status = quotedStatus; + } else { + values.put(Statuses.MY_RETWEET_ID, orig.getCurrentUserRetweet()); + status = orig; + } + final User user = status.getUser(); + final long userId = user.getId(); + final String profileImageUrl = (user.getProfileImageUrlHttps()); + final String name = user.getName(), screenName = user.getScreenName(); + values.put(Statuses.USER_ID, userId); + values.put(Statuses.USER_NAME, name); + values.put(Statuses.USER_SCREEN_NAME, screenName); + values.put(Statuses.IS_PROTECTED, user.isProtected()); + values.put(Statuses.IS_VERIFIED, user.isVerified()); + values.put(Statuses.USER_PROFILE_IMAGE_URL, profileImageUrl); + values.put(CachedUsers.IS_FOLLOWING, user.isFollowing()); + final String textHtml = TwitterContentUtils.formatStatusText(status); + values.put(Statuses.TEXT_HTML, textHtml); + values.put(Statuses.TEXT_PLAIN, status.getText()); + values.put(Statuses.TEXT_UNESCAPED, toPlainText(textHtml)); + values.put(Statuses.RETWEET_COUNT, status.getRetweetCount()); + values.put(Statuses.REPLY_COUNT, status.getReplyCount()); + values.put(Statuses.FAVORITE_COUNT, status.getFavoriteCount()); + values.put(Statuses.DESCENDENT_REPLY_COUNT, status.getDescendentReplyCount()); + values.put(Statuses.IN_REPLY_TO_STATUS_ID, status.getInReplyToStatusId()); + values.put(Statuses.IN_REPLY_TO_USER_ID, status.getInReplyToUserId()); + values.put(Statuses.IN_REPLY_TO_USER_NAME, TwitterContentUtils.getInReplyToName(status)); + values.put(Statuses.IN_REPLY_TO_USER_SCREEN_NAME, status.getInReplyToScreenName()); + values.put(Statuses.SOURCE, status.getSource()); + values.put(Statuses.IS_POSSIBLY_SENSITIVE, status.isPossiblySensitive()); + final GeoLocation location = status.getGeoLocation(); + if (location != null) { + values.put(Statuses.LOCATION, ParcelableLocation.toString(location.getLatitude(), location.getLongitude())); + } + final Place place = status.getPlace(); + if (place != null) { + values.put(Statuses.PLACE_FULL_NAME, place.getFullName()); + } + values.put(Statuses.IS_FAVORITE, status.isFavorited()); + final ParcelableMedia[] media = ParcelableMedia.fromEntities(status); + if (media != null) { + values.put(Statuses.MEDIA_LIST, SimpleValueSerializer.toSerializedString(media)); + } + final ParcelableUserMention[] mentions = ParcelableUserMention.fromStatus(status); + if (mentions != null) { + values.put(Statuses.MENTIONS_LIST, SimpleValueSerializer.toSerializedString(mentions)); + } + final ParcelableCardEntity card = ParcelableCardEntity.fromCardEntity(status.getCard(), accountId); + if (card != null) { + values.put(Statuses.CARD_NAME, card.name); + values.put(Statuses.CARD, JSONSerializer.toJSONObjectString(card)); + } + return values; + } + + public static ContentValues createStatusDraft(final ParcelableStatusUpdate status) { + return createStatusDraft(status, ParcelableAccount.getAccountIds(status.accounts)); + } + + public static ContentValues createStatusDraft(final ParcelableStatusUpdate status, + final long[] accountIds) { + final ContentValues values = new ContentValues(); + values.put(Drafts.ACTION_TYPE, Drafts.ACTION_UPDATE_STATUS); + values.put(Drafts.TEXT, status.text); + values.put(Drafts.ACCOUNT_IDS, TwidereArrayUtils.toString(accountIds, ',', false)); + values.put(Drafts.IN_REPLY_TO_STATUS_ID, status.in_reply_to_status_id); + values.put(Drafts.LOCATION, ParcelableLocation.toString(status.location)); + values.put(Drafts.IS_POSSIBLY_SENSITIVE, status.is_possibly_sensitive); + values.put(Drafts.TIMESTAMP, System.currentTimeMillis()); + if (status.media != null) { + values.put(Drafts.MEDIA, JSONSerializer.toJSONArrayString(status.media)); + } + return values; + } + + public static ContentValues[] createTrends(final List trendsList) { + if (trendsList == null) return new ContentValues[0]; + final List resultList = new ArrayList<>(); + for (final Trends trends : trendsList) { + final long timestamp = trends.getTrendAt().getTime(); + for (final Trend trend : trends.getTrends()) { + final ContentValues values = new ContentValues(); + values.put(CachedTrends.NAME, trend.getName()); + values.put(CachedTrends.TIMESTAMP, timestamp); + resultList.add(values); + } + } + return resultList.toArray(new ContentValues[resultList.size()]); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlBuilder.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlBuilder.java new file mode 100644 index 00000000..cbd63c64 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlBuilder.java @@ -0,0 +1,217 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Locale; + +import static android.text.TextUtils.isEmpty; +import static org.getlantern.firetweet.util.HtmlEscapeHelper.escape; +import static org.getlantern.firetweet.util.HtmlEscapeHelper.toHtml; +import static org.getlantern.firetweet.util.HtmlEscapeHelper.unescape; + +public class HtmlBuilder { + + private final String source; + private final int[] codePoints; + private final int codePointsLength; + private final boolean throwExceptions, sourceIsEscaped, shouldReEscape; + + private final ArrayList links = new ArrayList<>(); + + public HtmlBuilder(final String source, final boolean strict, final boolean sourceIsEscaped, + final boolean shouldReEscape) { + if (source == null) throw new NullPointerException(); + this.source = source; + final int length = source.length(); + final int[] codepointsTemp = new int[length]; + int codePointsLength = 0; + for (int offset = 0; offset < length; ) { + final int codepoint = source.codePointAt(offset); + codepointsTemp[codePointsLength++] = codepoint; + offset += Character.charCount(codepoint); + } + codePoints = new int[codePointsLength]; + System.arraycopy(codepointsTemp, 0, codePoints, 0, codePointsLength); + throwExceptions = strict; + this.sourceIsEscaped = sourceIsEscaped; + this.shouldReEscape = shouldReEscape; + this.codePointsLength = codePointsLength; + } + + public boolean addLink(final String link, final String display, final int start, final int end) { + return addLink(link, display, start, end, false); + } + + public boolean addLink(final String link, final String display, final int start, final int end, + final boolean display_is_html) { + if (start < 0 || end < 0 || start > end || end > codePointsLength) { + final String message = String.format(Locale.US, "text:%s, length:%d, start:%d, end:%d", source, + codePointsLength, start, end); + if (throwExceptions) throw new StringIndexOutOfBoundsException(message); + return false; + } + if (hasLink(start, end)) { + final String message = String.format(Locale.US, + "link already added in this range! text:%s, link:%s, display:%s, start:%d, end:%d", source, link, + display, start, end); + if (throwExceptions) throw new IllegalArgumentException(message); + return false; + } + return links.add(new LinkSpec(link, display, start, end, display_is_html)); + } + + public String build() { + if (links.isEmpty()) return escapeSource(source); + Collections.sort(links); + final StringBuilder builder = new StringBuilder(); + final int linksSize = links.size(); + for (int i = 0; i < linksSize; i++) { + final LinkSpec spec = links.get(i); + if (spec == null) { + continue; + } + final int start = spec.start, end = spec.end; + if (i == 0) { + if (start >= 0 && start <= codePointsLength) { + appendSource(builder, 0, start); + } + } else if (i > 0) { + final int lastEnd = links.get(i - 1).end; + if (lastEnd >= 0 && lastEnd <= start && start <= codePointsLength) { + appendSource(builder, lastEnd, start); + } + } + builder.append(""); + if (start >= 0 && start <= end && end <= codePointsLength) { + builder.append(!isEmpty(spec.display) ? spec.display_is_html ? spec.display : toHtml(spec.display) + : spec.link); + } + builder.append(""); + if (i == linksSize - 1 && end >= 0 && end <= codePointsLength) { + appendSource(builder, end, codePointsLength); + } + } + return builder.toString(); + } + + public boolean hasLink(final int start, final int end) { + for (final LinkSpec spec : links) { + if (start >= spec.start && start <= spec.end || end >= spec.start && end <= spec.end) + return true; + } + return false; + } + + @Override + public String toString() { + return "HtmlBuilder{orig=" + source + ", codePoints=" + Arrays.toString(codePoints) + ", string_length=" + + codePointsLength + ", throw_exceptions=" + throwExceptions + ", source_is_escaped=" + sourceIsEscaped + + ", should_re_escape=" + shouldReEscape + ", links=" + links + "}"; + } + + private void appendSource(final StringBuilder builder, final int start, final int end) { + if (sourceIsEscaped == shouldReEscape) { + for (int i = start; i < end; i++) { + builder.appendCodePoint(codePoints[i]); + } + } else if (shouldReEscape) { + builder.append(escape(subString(start, end))); + } else { + builder.append(unescape(subString(start, end))); + } + } + + private String escapeSource(final String source) { + if (sourceIsEscaped == shouldReEscape) return source; + return shouldReEscape ? escape(source) : unescape(source); + } + + private String subString(final int start, final int end) { + final StringBuilder sb = new StringBuilder(); + for (int i = start; i < end; i++) { + sb.appendCodePoint(codePoints[i]); + } + return sb.toString(); + } + + static final class LinkSpec implements Comparable { + + final String link, display; + final int start, end; + final boolean display_is_html; + + LinkSpec(final String link, final String display, final int start, final int end, final boolean display_is_html) { + this.link = link; + this.display = display; + this.start = start; + this.end = end; + this.display_is_html = display_is_html; + } + + @Override + public int compareTo(@NonNull final LinkSpec that) { + return start - that.start; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof LinkSpec)) return false; + final LinkSpec other = (LinkSpec) obj; + if (display == null) { + if (other.display != null) return false; + } else if (!display.equals(other.display)) return false; + if (display_is_html != other.display_is_html) return false; + if (end != other.end) return false; + if (link == null) { + if (other.link != null) return false; + } else if (!link.equals(other.link)) return false; + if (start != other.start) return false; + return true; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (display == null ? 0 : display.hashCode()); + result = prime * result + (display_is_html ? 1231 : 1237); + result = prime * result + end; + result = prime * result + (link == null ? 0 : link.hashCode()); + result = prime * result + start; + return result; + } + + @Override + public String toString() { + return "LinkSpec{link=" + link + ", display=" + display + ", start=" + start + ", end=" + end + + ", display_is_html=" + display_is_html + "}"; + } + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlEscapeHelper.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlEscapeHelper.java new file mode 100644 index 00000000..f499a04e --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlEscapeHelper.java @@ -0,0 +1,46 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import org.apache.commons.lang3.StringEscapeUtils; + +public class HtmlEscapeHelper { + + public static String escape(final String string) { + if (string == null) return null; + return StringEscapeUtils.escapeHtml4(string); + } + + public static String toHtml(final String string) { + if (string == null) return null; + return escape(string).replace("\n", "
"); + } + + public static String toPlainText(final String string) { + if (string == null) return null; + return unescape(string.replace("
", "\n").replaceAll("|<[^>]+>", "")); + } + + public static String unescape(final String string) { + if (string == null) return null; + return StringEscapeUtils.unescapeHtml4(string); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlLinkExtractor.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlLinkExtractor.java new file mode 100644 index 00000000..3fe0349c --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/HtmlLinkExtractor.java @@ -0,0 +1,85 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HtmlLinkExtractor { + + private final Pattern patternTag, patternLink; + + private static final String HTML_A_TAG_PATTERN = "(?i)]+)>(.+?)"; + private static final String HTML_A_HREF_TAG_PATTERN = "\\s*(?i)href\\s*=\\s*(\"([^\"]*\")|'[^']*'|([^'\">\\s]+))"; + + public HtmlLinkExtractor() { + patternTag = Pattern.compile(HTML_A_TAG_PATTERN); + patternLink = Pattern.compile(HTML_A_HREF_TAG_PATTERN); + } + + /** + * Validate html with regular expression + * + * @param html html content for validation + * @return Vector links and link text + */ + public Vector grabLinks(final String html) { + final Vector result = new Vector(); + final Matcher matcherTag = patternTag.matcher(html); + while (matcherTag.find()) { + final String href = matcherTag.group(1); // href + final String linkText = matcherTag.group(2); // link text + final Matcher matcherLink = patternLink.matcher(href); + while (matcherLink.find()) { + final String link = matcherLink.group(1); // link + final HtmlLink obj = new HtmlLink(link, linkText); + result.add(obj); + } + } + return result; + } + + public static class HtmlLink { + + private final String link; + private final String text; + + private HtmlLink(final String link, final String text) { + this.link = replaceInvalidChar(link); + this.text = text; + } + + public String getLink() { + return link; + } + + public String getLinkText() { + return text; + } + + private static String replaceInvalidChar(String link) { + link = link.replaceAll("'", ""); + link = link.replaceAll("\"", ""); + return link; + } + + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/MediaPreviewUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/MediaPreviewUtils.java new file mode 100644 index 00000000..ad128400 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/MediaPreviewUtils.java @@ -0,0 +1,397 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import org.json.JSONException; +import org.json.JSONObject; +import org.getlantern.firetweet.model.ParcelableMedia; +import org.getlantern.firetweet.util.HtmlLinkExtractor.HtmlLink; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import twitter4j.MediaEntity; +import twitter4j.Status; +import twitter4j.TwitterException; +import twitter4j.URLEntity; +import twitter4j.http.HttpClientWrapper; +import twitter4j.http.HttpParameter; +import twitter4j.http.HttpResponse; + +import static android.text.TextUtils.isEmpty; + +public class MediaPreviewUtils { + + public static final String AVAILABLE_URL_SCHEME_PREFIX = "(https?:\\/\\/)?"; + public static final String AVAILABLE_IMAGE_SHUFFIX = "(png|jpeg|jpg|gif|bmp)"; + public static final String SINA_WEIBO_IMAGES_AVAILABLE_SIZES = "(woriginal|large|thumbnail|bmiddle|wap[\\d]+|mw[\\d]+)"; + public static final String GOOGLE_IMAGES_AVAILABLE_SIZES = "((([whs]\\d+|no)\\-?)+)"; + + private static final String STRING_PATTERN_TWITTER_IMAGES_DOMAIN = "(p|pbs)\\.twimg\\.com"; + private static final String STRING_PATTERN_TWITTER_TON_DOMAIN = "(ton)\\.twitter\\.com"; + private static final String STRING_PATTERN_SINA_WEIBO_IMAGES_DOMAIN = "[\\w\\d]+\\.sinaimg\\.cn|[\\w\\d]+\\.sina\\.cn"; + private static final String STRING_PATTERN_LOCKERZ_DOMAIN = "lockerz\\.com"; + private static final String STRING_PATTERN_PLIXI_DOMAIN = "plixi\\.com"; + private static final String STRING_PATTERN_INSTAGRAM_DOMAIN = "instagr\\.am|instagram\\.com"; + private static final String STRING_PATTERN_TWITPIC_DOMAIN = "twitpic\\.com"; + private static final String STRING_PATTERN_IMGLY_DOMAIN = "img\\.ly"; + private static final String STRING_PATTERN_YFROG_DOMAIN = "yfrog\\.com"; + private static final String STRING_PATTERN_TWITGOO_DOMAIN = "twitgoo\\.com"; + private static final String STRING_PATTERN_MOBYPICTURE_DOMAIN = "moby\\.to"; + private static final String STRING_PATTERN_IMGUR_DOMAIN = "imgur\\.com|i\\.imgur\\.com"; + private static final String STRING_PATTERN_PHOTOZOU_DOMAIN = "photozou\\.jp"; + private static final String STRING_PATTERN_GOOGLE_IMAGES_DOMAIN = "(lh|gp|s)(\\d+)?\\.(ggpht|googleusercontent)\\.com"; + + private static final String STRING_PATTERN_IMAGES_NO_SCHEME = "[^:\\/\\/].+?\\." + AVAILABLE_IMAGE_SHUFFIX; + private static final String STRING_PATTERN_TWITTER_IMAGES_NO_SCHEME = STRING_PATTERN_TWITTER_IMAGES_DOMAIN + + "(\\/media)?\\/([\\d\\w\\-_]+)\\." + AVAILABLE_IMAGE_SHUFFIX; + private static final String STRING_PATTERN_SINA_WEIBO_IMAGES_NO_SCHEME = "(" + + STRING_PATTERN_SINA_WEIBO_IMAGES_DOMAIN + ")" + "\\/" + SINA_WEIBO_IMAGES_AVAILABLE_SIZES + + "\\/(([\\d\\w]+)\\." + AVAILABLE_IMAGE_SHUFFIX + ")"; + private static final String STRING_PATTERN_LOCKERZ_NO_SCHEME = "(" + STRING_PATTERN_LOCKERZ_DOMAIN + ")" + + "\\/s\\/(\\w+)\\/?"; + private static final String STRING_PATTERN_PLIXI_NO_SCHEME = "(" + STRING_PATTERN_PLIXI_DOMAIN + ")" + + "\\/p\\/(\\w+)\\/?"; + private static final String STRING_PATTERN_INSTAGRAM_NO_SCHEME = "(" + STRING_PATTERN_INSTAGRAM_DOMAIN + ")" + + "\\/p\\/([_\\-\\d\\w]+)\\/?"; + private static final String STRING_PATTERN_TWITPIC_NO_SCHEME = STRING_PATTERN_TWITPIC_DOMAIN + "\\/([\\d\\w]+)\\/?"; + private static final String STRING_PATTERN_IMGLY_NO_SCHEME = STRING_PATTERN_IMGLY_DOMAIN + "\\/([\\w\\d]+)\\/?"; + private static final String STRING_PATTERN_YFROG_NO_SCHEME = STRING_PATTERN_YFROG_DOMAIN + "\\/([\\w\\d]+)\\/?"; + private static final String STRING_PATTERN_TWITGOO_NO_SCHEME = STRING_PATTERN_TWITGOO_DOMAIN + "\\/([\\d\\w]+)\\/?"; + private static final String STRING_PATTERN_MOBYPICTURE_NO_SCHEME = STRING_PATTERN_MOBYPICTURE_DOMAIN + + "\\/([\\d\\w]+)\\/?"; + private static final String STRING_PATTERN_IMGUR_NO_SCHEME = "(" + STRING_PATTERN_IMGUR_DOMAIN + ")" + + "\\/([\\d\\w]+)((?-i)s|(?-i)l)?(\\." + AVAILABLE_IMAGE_SHUFFIX + ")?"; + private static final String STRING_PATTERN_PHOTOZOU_NO_SCHEME = STRING_PATTERN_PHOTOZOU_DOMAIN + + "\\/photo\\/show\\/([\\d]+)\\/([\\d]+)\\/?"; + private static final String STRING_PATTERN_GOOGLE_IMAGES_NO_SCHEME = "(" + STRING_PATTERN_GOOGLE_IMAGES_DOMAIN + + ")" + "((\\/[\\w\\d\\-\\_]+)+)\\/" + GOOGLE_IMAGES_AVAILABLE_SIZES + "\\/.+"; + private static final String STRING_PATTERN_GOOGLE_PROXY_IMAGES_NO_SCHEME = "(" + + STRING_PATTERN_GOOGLE_IMAGES_DOMAIN + ")" + "\\/proxy\\/([\\w\\d\\-\\_]+)=" + + GOOGLE_IMAGES_AVAILABLE_SIZES; + + private static final String STRING_PATTERN_IMAGES = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_IMAGES_NO_SCHEME; + private static final String STRING_PATTERN_TWITTER_IMAGES = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_TWITTER_IMAGES_NO_SCHEME; + private static final String STRING_PATTERN_SINA_WEIBO_IMAGES = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_SINA_WEIBO_IMAGES_NO_SCHEME; + private static final String STRING_PATTERN_LOCKERZ = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_LOCKERZ_NO_SCHEME; + private static final String STRING_PATTERN_PLIXI = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_PLIXI_NO_SCHEME; + private static final String STRING_PATTERN_INSTAGRAM = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_INSTAGRAM_NO_SCHEME; + private static final String STRING_PATTERN_TWITPIC = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_TWITPIC_NO_SCHEME; + private static final String STRING_PATTERN_IMGLY = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_IMGLY_NO_SCHEME; + private static final String STRING_PATTERN_YFROG = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_YFROG_NO_SCHEME; + private static final String STRING_PATTERN_TWITGOO = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_TWITGOO_NO_SCHEME; + private static final String STRING_PATTERN_MOBYPICTURE = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_MOBYPICTURE_NO_SCHEME; + private static final String STRING_PATTERN_IMGUR = AVAILABLE_URL_SCHEME_PREFIX + STRING_PATTERN_IMGUR_NO_SCHEME; + private static final String STRING_PATTERN_PHOTOZOU = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_PHOTOZOU_NO_SCHEME; + private static final String STRING_PATTERN_GOOGLE_IMAGES = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_GOOGLE_IMAGES_NO_SCHEME; + private static final String STRING_PATTERN_GOOGLE_PROXY_IMAGES = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_GOOGLE_PROXY_IMAGES_NO_SCHEME; + private static final String STRING_PATTERN_TWITTER_DM_IMAGES = AVAILABLE_URL_SCHEME_PREFIX + + STRING_PATTERN_TWITTER_IMAGES_NO_SCHEME; + + public static final Pattern PATTERN_TWITTER_IMAGES = Pattern.compile(STRING_PATTERN_TWITTER_IMAGES, + Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_TWITTER_DM_IMAGES = Pattern.compile(STRING_PATTERN_TWITTER_DM_IMAGES, + Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_SINA_WEIBO_IMAGES = Pattern.compile(STRING_PATTERN_SINA_WEIBO_IMAGES, + Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_LOCKERZ = Pattern.compile(STRING_PATTERN_LOCKERZ, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_PLIXI = Pattern.compile(STRING_PATTERN_PLIXI, Pattern.CASE_INSENSITIVE); + + public static final Pattern PATTERN_INSTAGRAM = Pattern.compile(STRING_PATTERN_INSTAGRAM, Pattern.CASE_INSENSITIVE); + public static final int INSTAGRAM_GROUP_ID = 3; + + public static final Pattern PATTERN_TWITPIC = Pattern.compile(STRING_PATTERN_TWITPIC, Pattern.CASE_INSENSITIVE); + public static final int TWITPIC_GROUP_ID = 2; + + public static final Pattern PATTERN_IMGLY = Pattern.compile(STRING_PATTERN_IMGLY, Pattern.CASE_INSENSITIVE); + public static final int IMGLY_GROUP_ID = 2; + + public static final Pattern PATTERN_YFROG = Pattern.compile(STRING_PATTERN_YFROG, Pattern.CASE_INSENSITIVE); + public static final int YFROG_GROUP_ID = 2; + + public static final Pattern PATTERN_TWITGOO = Pattern.compile(STRING_PATTERN_TWITGOO, Pattern.CASE_INSENSITIVE); + public static final int TWITGOO_GROUP_ID = 2; + + public static final Pattern PATTERN_MOBYPICTURE = Pattern.compile(STRING_PATTERN_MOBYPICTURE, + Pattern.CASE_INSENSITIVE); + public static final int MOBYPICTURE_GROUP_ID = 2; + + public static final Pattern PATTERN_IMGUR = Pattern.compile(STRING_PATTERN_IMGUR, Pattern.CASE_INSENSITIVE); + public static final int IMGUR_GROUP_ID = 3; + + public static final Pattern PATTERN_PHOTOZOU = Pattern.compile(STRING_PATTERN_PHOTOZOU, Pattern.CASE_INSENSITIVE); + public static final int PHOTOZOU_GROUP_ID = 3; + + public static final Pattern PATTERN_GOOGLE_IMAGES = Pattern.compile(STRING_PATTERN_GOOGLE_IMAGES, + Pattern.CASE_INSENSITIVE); + public static final int GOOGLE_IMAGES_GROUP_SERVER = 2; + public static final int GOOGLE_IMAGES_GROUP_ID = 6; + + public static final Pattern PATTERN_GOOGLE_PROXY_IMAGES = Pattern.compile(STRING_PATTERN_GOOGLE_PROXY_IMAGES, + Pattern.CASE_INSENSITIVE); + public static final int GOOGLE_PROXY_IMAGES_GROUP_SERVER = 2; + public static final int GOOGLE_PROXY_IMAGES_GROUP_ID = 6; + + private static final Pattern[] SUPPORTED_PATTERNS = {PATTERN_TWITTER_IMAGES, PATTERN_INSTAGRAM, + PATTERN_GOOGLE_IMAGES, PATTERN_GOOGLE_PROXY_IMAGES, PATTERN_SINA_WEIBO_IMAGES, PATTERN_TWITPIC, + PATTERN_IMGUR, PATTERN_IMGLY, PATTERN_YFROG, PATTERN_LOCKERZ, PATTERN_PLIXI, PATTERN_TWITGOO, + PATTERN_MOBYPICTURE, PATTERN_PHOTOZOU, PATTERN_TWITTER_DM_IMAGES}; + + private static final String URL_PHOTOZOU_PHOTO_INFO = "https://api.photozou.jp/rest/photo_info.json"; + + public static ParcelableMedia getAllAvailableImage(final String link, final boolean fullImage) { + try { + return getAllAvailableImage(link, fullImage, null); + } catch (final IOException e) { + throw new AssertionError("This should never happen"); + } + } + + public static ParcelableMedia getAllAvailableImage(final String link, final boolean fullImage, + final HttpClientWrapper client) throws IOException { + if (link == null) return null; + Matcher m; + m = PATTERN_TWITTER_IMAGES.matcher(link); + if (m.matches()) return getTwitterImage(link, fullImage); + m = PATTERN_INSTAGRAM.matcher(link); + if (m.matches()) + return getInstagramImage(RegexUtils.matcherGroup(m, INSTAGRAM_GROUP_ID), link, fullImage); + m = PATTERN_GOOGLE_IMAGES.matcher(link); + if (m.matches()) + return getGoogleImage(RegexUtils.matcherGroup(m, GOOGLE_IMAGES_GROUP_SERVER), RegexUtils.matcherGroup(m, GOOGLE_IMAGES_GROUP_ID), + fullImage); + m = PATTERN_GOOGLE_PROXY_IMAGES.matcher(link); + if (m.matches()) + return getGoogleProxyImage(RegexUtils.matcherGroup(m, GOOGLE_PROXY_IMAGES_GROUP_SERVER), + RegexUtils.matcherGroup(m, GOOGLE_PROXY_IMAGES_GROUP_ID), fullImage); + m = PATTERN_SINA_WEIBO_IMAGES.matcher(link); + if (m.matches()) return getSinaWeiboImage(link, fullImage); + m = PATTERN_TWITPIC.matcher(link); + if (m.matches()) + return getTwitpicImage(RegexUtils.matcherGroup(m, TWITPIC_GROUP_ID), link, fullImage); + m = PATTERN_IMGUR.matcher(link); + if (m.matches()) + return getImgurImage(RegexUtils.matcherGroup(m, IMGUR_GROUP_ID), link, fullImage); + m = PATTERN_IMGLY.matcher(link); + if (m.matches()) + return getImglyImage(RegexUtils.matcherGroup(m, IMGLY_GROUP_ID), link, fullImage); + m = PATTERN_YFROG.matcher(link); + if (m.matches()) + return getYfrogImage(RegexUtils.matcherGroup(m, YFROG_GROUP_ID), link, fullImage); + m = PATTERN_LOCKERZ.matcher(link); + if (m.matches()) return getLockerzAndPlixiImage(link, fullImage); + m = PATTERN_PLIXI.matcher(link); + if (m.matches()) return getLockerzAndPlixiImage(link, fullImage); + m = PATTERN_TWITGOO.matcher(link); + if (m.matches()) + return getTwitgooImage(RegexUtils.matcherGroup(m, TWITGOO_GROUP_ID), link, fullImage); + m = PATTERN_MOBYPICTURE.matcher(link); + if (m.matches()) + return getMobyPictureImage(RegexUtils.matcherGroup(m, MOBYPICTURE_GROUP_ID), link, fullImage); + m = PATTERN_PHOTOZOU.matcher(link); + if (m.matches()) + return getPhotozouImage(client, RegexUtils.matcherGroup(m, PHOTOZOU_GROUP_ID), link, fullImage); + return null; + } + + public static ParcelableMedia[] getImagesInStatus(final String status_string, final boolean fullImage) { + if (status_string == null) return new ParcelableMedia[0]; + final List images = new ArrayList<>(); + final HtmlLinkExtractor extractor = new HtmlLinkExtractor(); + for (final HtmlLink link : extractor.grabLinks(status_string)) { + final ParcelableMedia spec = getAllAvailableImage(link.getLink(), fullImage); + if (spec != null) { + images.add(spec); + } + } + return images.toArray(new ParcelableMedia[images.size()]); + } + + public static String getSupportedFirstLink(final Status status) { + if (status == null) return null; + final MediaEntity[] mediaEntities = status.getMediaEntities(); + if (mediaEntities != null) { + for (final MediaEntity mediaEntity : mediaEntities) { + final String expanded = mediaEntity.getMediaURLHttps(); + if (getSupportedLink(expanded) != null) return expanded; + } + } + final URLEntity[] urlEntities = status.getURLEntities(); + if (urlEntities != null) { + for (final URLEntity urlEntity : urlEntities) { + final String expanded = urlEntity.getExpandedURL(); + if (getSupportedLink(expanded) != null) return expanded; + } + } + return null; + } + + public static String getSupportedFirstLink(final String html) { + if (html == null) return null; + final HtmlLinkExtractor extractor = new HtmlLinkExtractor(); + for (final HtmlLink link : extractor.grabLinks(html)) { + if (getSupportedLink(link.getLink()) != null) return link.getLink(); + } + return null; + } + + public static String getSupportedLink(final String link) { + if (link == null) return null; + for (final Pattern pattern : SUPPORTED_PATTERNS) { + if (pattern.matcher(link).matches()) return link; + } + return null; + } + + public static List getSupportedLinksInStatus(final String statusString) { + if (statusString == null) return Collections.emptyList(); + final List links = new ArrayList<>(); + final HtmlLinkExtractor extractor = new HtmlLinkExtractor(); + for (final HtmlLink link : extractor.grabLinks(statusString)) { + final String spec = getSupportedLink(link.getLink()); + if (spec != null) { + links.add(spec); + } + } + return links; + } + + public static boolean isLinkSupported(final String link) { + if (link == null) return false; + for (final Pattern pattern : SUPPORTED_PATTERNS) { + if (pattern.matcher(link).matches()) return true; + } + return false; + } + + private static ParcelableMedia getGoogleImage(final String server, final String id, final boolean fullImage) { + if (isEmpty(server) || isEmpty(id)) return null; + final String full = "https://" + server + id + "/s0/full"; + final String preview = fullImage ? full : "https://" + server + id + "/s480/full"; + return ParcelableMedia.newImage(preview, full); + } + + private static ParcelableMedia getGoogleProxyImage(final String server, final String id, final boolean fullImage) { + if (isEmpty(server) || isEmpty(id)) return null; + final String full = "https://" + server + "/proxy/" + id + "=s0"; + final String preview = fullImage ? full : "https://" + server + "/proxy/" + id + "=s480"; + return ParcelableMedia.newImage(preview, full); + } + + private static ParcelableMedia getImglyImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = String.format("http://img.ly/show/%s/%s", fullImage ? "full" : "medium", id); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getImgurImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = fullImage ? String.format("http://i.imgur.com/%s.jpg", id) : String.format( + "http://i.imgur.com/%sl.jpg", id); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getInstagramImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = String.format("https://instagram.com/p/%s/media/?size=%s", id, fullImage ? "l" : "m"); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getLockerzAndPlixiImage(final String url, final boolean fullImage) { + if (isEmpty(url)) return null; + final String preview = String.format("https://api.plixi.com/api/tpapi.svc/imagefromurl?url=%s&size=%s", url, + fullImage ? "big" : "small"); + return ParcelableMedia.newImage(preview, url); + + } + + private static ParcelableMedia getMobyPictureImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = String.format("http://moby.to/%s:%s", id, fullImage ? "full" : "thumb"); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getPhotozouImage(final HttpClientWrapper client, final String id, final String orig, + final boolean fullImage) throws IOException { + if (isEmpty(id)) return null; + if (client != null) { + try { + final HttpParameter[] parameters = {new HttpParameter("photo_id", id)}; + final HttpResponse resp = client.get(URL_PHOTOZOU_PHOTO_INFO, URL_PHOTOZOU_PHOTO_INFO, parameters); + final JSONObject json = resp.asJSONObject().getJSONObject("info").getJSONObject("photo"); + final String key = fullImage ? "original_image_url" : "image_url"; + return ParcelableMedia.newImage(json.getString(key), orig); + } catch (final TwitterException e) { + return null; + } catch (final JSONException e) { + throw new IOException(e); + } + } + final String preview = String.format(Locale.US, "http://photozou.jp/p/img/%s", id); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getSinaWeiboImage(final String url, final boolean fullImage) { + if (isEmpty(url)) return null; + final String full = url.replaceAll("/" + SINA_WEIBO_IMAGES_AVAILABLE_SIZES + "/", "/woriginal/"); + final String preview = fullImage ? full : url.replaceAll("/" + SINA_WEIBO_IMAGES_AVAILABLE_SIZES + "/", + "/bmiddle/"); + return ParcelableMedia.newImage(preview, full); + } + + private static ParcelableMedia getTwitgooImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = String.format("http://twitgoo.com/show/%s/%s", fullImage ? "img" : "thumb", id); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getTwitpicImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = String.format("http://twitpic.com/show/%s/%s", fullImage ? "large" : "thumb", id); + return ParcelableMedia.newImage(preview, orig); + } + + private static ParcelableMedia getTwitterImage(final String url, final boolean fullImage) { + if (isEmpty(url)) return null; + final String full = (url + ":large").replaceFirst("https?://", "https://"); + final String preview = fullImage ? full : (url + ":medium").replaceFirst("https?://", "https://"); + return ParcelableMedia.newImage(preview, full); + } + + private static ParcelableMedia getYfrogImage(final String id, final String orig, final boolean fullImage) { + if (isEmpty(id)) return null; + final String preview = String.format("http://yfrog.com/%s:%s", id, fullImage ? "medium" : "iphone"); + return ParcelableMedia.newImage(preview, orig); + + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/ParseUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/ParseUtils.java new file mode 100644 index 00000000..5d7c19a8 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/ParseUtils.java @@ -0,0 +1,222 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import android.graphics.Color; +import android.os.Bundle; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; +import org.getlantern.firetweet.TwidereConstants; +import org.getlantern.firetweet.constant.IntentConstants; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; + +import static android.text.TextUtils.isEmpty; + +public final class ParseUtils { + + public static String bundleToJSON(final Bundle args) { + final Set keys = args.keySet(); + final JSONObject json = new JSONObject(); + for (final String key : keys) { + final Object value = args.get(key); + if (value == null) { + continue; + } + try { + if (value instanceof Boolean) { + json.put(key, args.getBoolean(key)); + } else if (value instanceof Integer) { + json.put(key, args.getInt(key)); + } else if (value instanceof Long) { + json.put(key, args.getLong(key)); + } else if (value instanceof String) { + json.put(key, args.getString(key)); + } else { + Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key); + } + } catch (final JSONException e) { + e.printStackTrace(); + } + } + return json.toString(); + } + + public static Bundle jsonToBundle(final String string) { + final Bundle bundle = new Bundle(); + if (string == null) return bundle; + try { + final JSONObject json = new JSONObject(string); + final Iterator it = json.keys(); + while (it.hasNext()) { + final Object key_obj = it.next(); + if (key_obj == null) { + continue; + } + final String key = key_obj.toString(); + final Object value = json.get(key); + if (value instanceof Boolean) { + bundle.putBoolean(key, json.optBoolean(key)); + } else if (value instanceof Integer) { + // Simple workaround for account_id + if (shouldPutLong(key)) { + bundle.putLong(key, json.optLong(key)); + } else { + bundle.putInt(key, json.optInt(key)); + } + } else if (value instanceof Long) { + bundle.putLong(key, json.optLong(key)); + } else if (value instanceof String) { + bundle.putString(key, json.optString(key)); + } else { + Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key); + } + } + } catch (final JSONException e) { + e.printStackTrace(); + } catch (final ClassCastException e) { + e.printStackTrace(); + } + return bundle; + } + + public static double parseDouble(final String source) { + return parseDouble(source, -1); + } + + public static double parseDouble(final String source, final double def) { + if (source == null) return def; + try { + return Double.parseDouble(source); + } catch (final NumberFormatException e) { + // Wrong number format? Ignore them. + } + return def; + } + + public static float parseFloat(final String source) { + return parseFloat(source, -1); + } + + public static float parseFloat(final String source, final float def) { + if (source == null) return def; + try { + return Float.parseFloat(source); + } catch (final NumberFormatException e) { + // Wrong number format? Ignore them. + } + return def; + } + + public static int parseInt(final String source) { + return parseInt(source, -1); + } + + public static int parseInt(final String source, final int def) { + if (source == null) return def; + try { + return Integer.valueOf(source); + } catch (final NumberFormatException e) { + // Wrong number format? Ignore them. + } + return def; + } + + public static long parseLong(final String source) { + return parseLong(source, -1); + } + + public static long parseLong(final String source, final long def) { + if (source == null) return def; + try { + return Long.parseLong(source); + } catch (final NumberFormatException e) { + // Wrong number format? Ignore them. + } + return def; + } + + @Deprecated + public static String parseString(final String object) { + return object; + } + + public static String parseString(final Object object) { + return parseString(object, null); + } + + public static String parseString(final Object object, final String def) { + if (object == null) return def; + return String.valueOf(object); + } + + public static URI parseURI(final String uriString) { + if (uriString == null) return null; + try { + return new URI(uriString); + } catch (final URISyntaxException e) { + // This should not happen. + } + return null; + } + + public static URL parseURL(final String urlString) { + if (urlString == null) return null; + try { + return new URL(urlString); + } catch (final MalformedURLException e) { + // This should not happen. + } + return null; + } + + private static boolean shouldPutLong(final String key) { + return IntentConstants.EXTRA_ACCOUNT_ID.equals(key) || IntentConstants.EXTRA_USER_ID.equals(key) || IntentConstants.EXTRA_STATUS_ID.equals(key) + || IntentConstants.EXTRA_LIST_ID.equals(key); + } + + public static String parsePrettyDecimal(double num, int decimalDigits) { + String result = String.format(Locale.US, "%." + decimalDigits + "f", num); + int dotIdx = result.lastIndexOf('.'); + if (dotIdx == -1) return result; + int i; + for (i = result.length() - 1; i >= 0; i--) { + if (result.charAt(i) != '0') break; + } + return result.substring(0, i == dotIdx ? dotIdx : i + 1); + } + + public static int parseColor(String str, int def) { + if (isEmpty(str)) return def; + try { + return Color.parseColor(str); + } catch (IllegalArgumentException e) { + return def; + } + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/RegexUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/RegexUtils.java new file mode 100644 index 00000000..3bbf3023 --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/RegexUtils.java @@ -0,0 +1,54 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import java.util.regex.Matcher; + +/** + * Created by mariotaku on 15/1/11. + */ +public class RegexUtils { + public static int matcherEnd(final Matcher matcher, final int group) { + try { + return matcher.end(group); + } catch (final IllegalStateException e) { + // Ignore. + } + return -1; + } + + public static String matcherGroup(final Matcher matcher, final int group) { + try { + return matcher.group(group); + } catch (final IllegalStateException e) { + // Ignore. + } + return null; + } + + public static int matcherStart(final Matcher matcher, final int group) { + try { + return matcher.start(group); + } catch (final IllegalStateException e) { + // Ignore. + } + return -1; + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/SimpleValueSerializer.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/SimpleValueSerializer.java new file mode 100644 index 00000000..6465b4cd --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/SimpleValueSerializer.java @@ -0,0 +1,230 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import android.util.Log; + +import org.getlantern.firetweet.TwidereConstants; + +import java.io.IOException; + +/** + * Created by mariotaku on 15/2/13. + */ +public class SimpleValueSerializer { + + private static final char ESCAPE = '\\'; + private static final char DIVIDER_ARRAY_ELEMENT = ';'; + private static final char DIVIDER_OBJECT_FIELD = ','; + private static final char DIVIDER_KEY_VALUE = '='; + + public static Reader newReader(String str) { + return new Reader(str); + } + + + private static T[] append(T[] old, int position, T item, Creator creator) { + T[] appended; + if (position < old.length) { + appended = old; + } else { + appended = creator.newArray(old.length * 2); + System.arraycopy(old, 0, appended, 0, old.length); + } + appended[position] = item; + return appended; + } + + + public static String escape(String str) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0, j = str.length(); i < j; i++) { + final char ch = str.charAt(i); + if (DIVIDER_ARRAY_ELEMENT == ch || ESCAPE == ch) { + sb.append(ESCAPE); + } + sb.append(ch); + } + return sb.toString(); + } + + @SafeVarargs + public static String toSerializedString(T... array) { + final Writer writer = newWriter(); + for (T item : array) { + writer.beginArrayElement(); + item.write(writer); + } + return writer.toString(); + } + + + public static T[] fromSerializedString(final String json, Creator creator) { + long start = System.nanoTime(); + T[] temp = creator.newArray(4); + try { + if (json == null) return null; + final SimpleValueSerializer.Reader reader = SimpleValueSerializer.newReader(json); + int count = 0; + while (reader.hasArrayElement()) { + final T item = creator.create(reader); + reader.endArrayElement(); + temp = append(temp, count++, item, creator); + } + final T[] result = creator.newArray(count); + System.arraycopy(temp, 0, result, 0, count); + return result; + } catch (final IOException e) { + e.printStackTrace(); + return null; + } + } + + public interface Creator { + T create(Reader reader) throws SerializationException; + + T[] newArray(int size); + } + + public static class SerializationException extends IOException { + + } + + public static Writer newWriter() { + return new Writer(); + } + + public static interface SimpleValueSerializable { + + void write(Writer writer); + } + + public static class Writer { + + private int keyValuesCount; + private final StringBuilder stringBuilder; + + public Writer() { + stringBuilder = new StringBuilder(); + keyValuesCount = 0; + } + + public void beginArrayElement() { + keyValuesCount = 0; + if (stringBuilder.length() > 0) { + stringBuilder.append(DIVIDER_ARRAY_ELEMENT); + } + } + + public void write(String key, String value) { + if (keyValuesCount++ > 0) { + stringBuilder.append(DIVIDER_OBJECT_FIELD); + } + stringBuilder.append(escape(key)); + stringBuilder.append(DIVIDER_KEY_VALUE); + stringBuilder.append(escape(value)); + } + + public String toString() { + return stringBuilder.toString(); + } + + public void write(String key, long value) { + write(key, String.valueOf(value)); + } + + public void write(String key, boolean value) { + write(key, String.valueOf(value)); + } + } + + public static class Reader { + private final String s; + private final int len; + private char lastToken; + private int cur; + + public Reader(String s) { + this.s = s; + this.len = s.length(); + cur = 0; + lastToken = '\0'; + } + + public boolean hasKeyValue() { + return (cur == 0 || (lastToken == '\0' || lastToken == DIVIDER_OBJECT_FIELD)) && cur < len; + } + + + public boolean hasArrayElement() { + return (cur == 0 || (lastToken == '\0' || lastToken == DIVIDER_ARRAY_ELEMENT)) && cur < len; + } + + public String nextKey() throws SerializationException { + if (lastToken != '\0' && lastToken != DIVIDER_OBJECT_FIELD) { + throw new SerializationException(); + } + return peek(); + } + + private String peek() { + StringBuilder sb = new StringBuilder(); + boolean isEscaped = false; + while (cur < len) { + char ch = s.charAt(cur++); + if (isEscaped) { + sb.append(ch); + isEscaped = false; + } else if (ch == ESCAPE) { + isEscaped = true; + } else if (ch == DIVIDER_KEY_VALUE || ch == DIVIDER_OBJECT_FIELD || ch == DIVIDER_ARRAY_ELEMENT) { + lastToken = ch; + break; + } else { + sb.append(ch); + } + } + return sb.toString(); + } + + public void skipValue() throws SerializationException { + nextString(); + } + + public String nextString() throws SerializationException { + if (lastToken != DIVIDER_KEY_VALUE) { + throw new SerializationException(); + } + return peek(); + } + + public int nextInt() throws SerializationException { + return Integer.parseInt(nextString()); + } + + public long nextLong() throws SerializationException { + return Long.parseLong(nextString()); + } + + public void endArrayElement() { + lastToken = '\0'; + } + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/TwidereArrayUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/TwidereArrayUtils.java new file mode 100644 index 00000000..dc839cbe --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/TwidereArrayUtils.java @@ -0,0 +1,232 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import org.apache.commons.lang3.ArrayUtils; + +import java.util.ArrayList; +import java.util.List; + +public final class TwidereArrayUtils { + + private TwidereArrayUtils() { + throw new AssertionError("You are trying to create an instance for this utility class!"); + } + + public static boolean contains(final Object[] array, final Object[] values) { + if (array == null || values == null) return false; + for (final Object value : values) { + if (!ArrayUtils.contains(array, value)) return false; + } + return true; + } + + public static boolean contentMatch(final long[] array1, final long[] array2) { + if (array1 == null || array2 == null) return array1 == array2; + if (array1.length != array2.length) return false; + final int length = array1.length; + for (int i = 0; i < length; i++) { + if (!ArrayUtils.contains(array2, array1[i])) return false; + } + return true; + } + + public static boolean contentMatch(final Object[] array1, final Object[] array2) { + if (array1 == null || array2 == null) return array1 == array2; + if (array1.length != array2.length) return false; + final int length = array1.length; + for (int i = 0; i < length; i++) { + if (!ArrayUtils.contains(array2, array1[i])) return false; + } + return true; + } + + public static long[] fromList(final List list) { + if (list == null) return null; + final int count = list.size(); + final long[] array = new long[count]; + for (int i = 0; i < count; i++) { + array[i] = list.get(i); + } + return array; + } + + + public static long[] intersection(final long[] array1, final long[] array2) { + if (array1 == null || array2 == null) return new long[0]; + final List list1 = new ArrayList(); + for (final long item : array1) { + list1.add(item); + } + final List list2 = new ArrayList(); + for (final long item : array2) { + list2.add(item); + } + list1.retainAll(list2); + return fromList(list1); + } + + public static void mergeArray(final Object[] dest, final Object[]... arrays) { + if (arrays == null || arrays.length == 0) return; + if (arrays.length == 1) { + final Object[] array = arrays[0]; + System.arraycopy(array, 0, dest, 0, array.length); + return; + } + for (int i = 0, j = arrays.length - 1; i < j; i++) { + final Object[] array1 = arrays[i], array2 = arrays[i + 1]; + System.arraycopy(array1, 0, dest, 0, array1.length); + System.arraycopy(array2, 0, dest, array1.length, array2.length); + } + } + + public static String mergeArrayToString(final String[] array) { + if (array == null) return null; + final StringBuilder builder = new StringBuilder(); + for (final String c : array) { + builder.append(c); + } + return builder.toString(); + } + + public static long min(final long[] array) { + if (array == null || array.length == 0) throw new IllegalArgumentException(); + long min = array[0]; + for (int i = 1, j = array.length; i < j; i++) { + if (min > array[i]) { + min = array[i]; + } + } + return min; + } + + @NonNull + public static long[] parseLongArray(final String string, final char token) { + if (TextUtils.isEmpty(string)) return new long[0]; + final String[] itemsStringArray = string.split(String.valueOf(token)); + final long[] array = new long[itemsStringArray.length]; + for (int i = 0, j = itemsStringArray.length; i < j; i++) { + try { + array[i] = Long.parseLong(itemsStringArray[i]); + } catch (final NumberFormatException e) { + return new long[0]; + } + } + return array; + } + + public static void reverse(@NonNull Object[] array) { + for (int i = 0; i < array.length / 2; i++) { + Object temp = array[i]; + array[i] = array[array.length - i - 1]; + array[array.length - i - 1] = temp; + } + } + + public static int[] subArray(final int[] array, final int start, final int end) { + final int length = end - start; + if (length < 0) throw new IllegalArgumentException(); + final int[] result = new int[length]; + System.arraycopy(array, start, result, 0, length); + return result; + } + + public static long[] subArray(final long[] array, final int start, final int end) { + final int length = end - start; + if (length < 0) throw new IllegalArgumentException(); + final long[] result = new long[length]; + System.arraycopy(array, start, result, 0, length); + return result; + } + + public static Object[] subArray(final Object[] array, final int start, final int end) { + final int length = end - start; + if (length < 0) throw new IllegalArgumentException(); + final Object[] result = new Object[length]; + System.arraycopy(array, start, result, 0, length); + return result; + } + + public static String[] subArray(final String[] array, final int start, final int end) { + final int length = end - start; + if (length < 0) throw new IllegalArgumentException(); + final String[] result = new String[length]; + System.arraycopy(array, start, result, 0, length); + return result; + } + + public static String toString(final long[] array, final char token, final boolean include_space) { + final StringBuilder builder = new StringBuilder(); + final int length = array.length; + for (int i = 0; i < length; i++) { + final String idString = String.valueOf(array[i]); + if (i > 0) { + builder.append(include_space ? token + " " : token); + } + builder.append(idString); + } + return builder.toString(); + } + + public static String toString(final Object[] array, final char token, final boolean include_space) { + final StringBuilder builder = new StringBuilder(); + final int length = array.length; + for (int i = 0; i < length; i++) { + final String id_string = String.valueOf(array[i]); + if (id_string != null) { + if (i > 0) { + builder.append(include_space ? token + " " : token); + } + builder.append(id_string); + } + } + return builder.toString(); + } + + public static String[] toStringArray(final Object[] array) { + if (array == null) return null; + final int length = array.length; + final String[] string_array = new String[length]; + for (int i = 0; i < length; i++) { + string_array[i] = ParseUtils.parseString(array[i]); + } + return string_array; + } + + public static String[] toStringArray(final String s) { + if (s == null) return null; + return s.split("(?!^)"); + } + + public static String toStringForSQL(final String[] array) { + final int size = array != null ? array.length : 0; + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < size; i++) { + if (i > 0) { + builder.append(','); + } + builder.append('?'); + } + return builder.toString(); + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/TwitterContentUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/TwitterContentUtils.java new file mode 100644 index 00000000..04df2ddc --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/TwitterContentUtils.java @@ -0,0 +1,146 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util; + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.getlantern.firetweet.common.R; + +import java.nio.charset.Charset; +import java.util.zip.CRC32; + +import twitter4j.DirectMessage; +import twitter4j.EntitySupport; +import twitter4j.MediaEntity; +import twitter4j.Status; +import twitter4j.URLEntity; +import twitter4j.User; +import twitter4j.UserMentionEntity; + +import static org.getlantern.firetweet.util.HtmlEscapeHelper.toPlainText; + +/** + * Created by mariotaku on 15/1/11. + */ +public class TwitterContentUtils { + public static String formatDirectMessageText(final DirectMessage message) { + if (message == null) return null; + final String text = message.getRawText(); + if (text == null) return null; + final HtmlBuilder builder = new HtmlBuilder(text, false, true, true); + TwitterContentUtils.parseEntities(builder, message); + return builder.build().replace("\n", "
"); + } + + public static String formatExpandedUserDescription(final User user) { + if (user == null) return null; + final String text = user.getDescription(); + if (text == null) return null; + final HtmlBuilder builder = new HtmlBuilder(text, false, true, true); + final URLEntity[] urls = user.getDescriptionEntities(); + if (urls != null) { + for (final URLEntity url : urls) { + final String expanded_url = url.getExpandedURL(); + if (expanded_url != null) { + builder.addLink(expanded_url, expanded_url, url.getStart(), url.getEnd()); + } + } + } + return toPlainText(builder.build().replace("\n", "
")); + } + + public static String formatStatusText(final Status status) { + if (status == null) return null; + final String text = status.getRawText(); + if (text == null) return null; + final HtmlBuilder builder = new HtmlBuilder(text, false, true, true); + TwitterContentUtils.parseEntities(builder, status); + return builder.build().replace("\n", "
"); + } + + public static String formatUserDescription(final User user) { + if (user == null) return null; + final String text = user.getDescription(); + if (text == null) return null; + final HtmlBuilder builder = new HtmlBuilder(text, false, true, true); + final URLEntity[] urls = user.getDescriptionEntities(); + if (urls != null) { + for (final URLEntity url : urls) { + final String expanded_url = url.getExpandedURL(); + if (expanded_url != null) { + builder.addLink(expanded_url, url.getDisplayURL(), url.getStart(), url.getEnd()); + } + } + } + return builder.build().replace("\n", "
"); + } + + @NonNull + public static String getInReplyToName(@NonNull final Status status) { + final Status orig = status.isRetweet() ? status.getRetweetedStatus() : status; + final long inReplyToUserId = status.getInReplyToUserId(); + final UserMentionEntity[] entities = status.getUserMentionEntities(); + if (entities == null) return orig.getInReplyToScreenName(); + for (final UserMentionEntity entity : entities) { + if (inReplyToUserId == entity.getId()) return entity.getName(); + } + return orig.getInReplyToScreenName(); + } + + public static boolean isOfficialKey(final Context context, final String consumerKey, + final String consumerSecret) { + if (context == null || consumerKey == null || consumerSecret == null) return false; + final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_secret_crc32); + final CRC32 crc32 = new CRC32(); + final byte[] consumerSecretBytes = consumerSecret.getBytes(Charset.forName("UTF-8")); + crc32.update(consumerSecretBytes, 0, consumerSecretBytes.length); + final long value = crc32.getValue(); + crc32.reset(); + for (final String keySecret : keySecrets) { + if (Long.parseLong(keySecret, 16) == value) return true; + } + return false; + } + + private static void parseEntities(final HtmlBuilder builder, final EntitySupport entities) { + // Format media. + final MediaEntity[] mediaEntities = entities.getMediaEntities(); + if (mediaEntities != null) { + for (final MediaEntity mediaEntity : mediaEntities) { + final int start = mediaEntity.getStart(), end = mediaEntity.getEnd(); + final String mediaUrl = mediaEntity.getMediaURL(); + if (mediaUrl != null && start >= 0 && end >= 0) { + builder.addLink(mediaUrl, mediaEntity.getDisplayURL(), start, end); + } + } + } + final URLEntity[] urlEntities = entities.getURLEntities(); + if (urlEntities != null) { + for (final URLEntity urlEntity : urlEntities) { + final int start = urlEntity.getStart(), end = urlEntity.getEnd(); + final String expandedUrl = urlEntity.getExpandedURL(); + if (expandedUrl != null && start >= 0 && end >= 0) { + builder.addLink(expandedUrl, urlEntity.getDisplayURL(), start, end); + } + } + } + } +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/content/ContentResolverUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/content/ContentResolverUtils.java new file mode 100644 index 00000000..f237ed9c --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/content/ContentResolverUtils.java @@ -0,0 +1,104 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util.content; + +import android.annotation.TargetApi; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.os.CancellationSignal; + +import org.getlantern.firetweet.util.TwidereArrayUtils; + +import java.util.Collection; + +import static android.text.TextUtils.isEmpty; + +public class ContentResolverUtils { + + public static final int MAX_BULK_COUNT = 128; + + public static int bulkDelete(final ContentResolver resolver, final Uri uri, final String inColumn, + final Collection colValues, final String extraWhere, final boolean valuesIsString) { + if (colValues == null) return 0; + return bulkDelete(resolver, uri, inColumn, colValues.toArray(), extraWhere, valuesIsString); + } + + public static int bulkDelete(final ContentResolver resolver, final Uri uri, final String inColumn, + final T[] colValues, final String extraWhere, final boolean valuesIsString) { + if (resolver == null || uri == null || isEmpty(inColumn) || colValues == null || colValues.length == 0) + return 0; + final int col_values_length = colValues.length, blocks_count = col_values_length / MAX_BULK_COUNT + 1; + int rows_deleted = 0; + for (int i = 0; i < blocks_count; i++) { + final int start = i * MAX_BULK_COUNT, end = Math.min(start + MAX_BULK_COUNT, col_values_length); + final String[] block = TwidereArrayUtils.toStringArray(TwidereArrayUtils.subArray(colValues, start, end)); + if (valuesIsString) { + final StringBuilder where = new StringBuilder(inColumn + " IN(" + TwidereArrayUtils.toStringForSQL(block) + + ")"); + if (!isEmpty(extraWhere)) { + where.append("AND ").append(extraWhere); + } + rows_deleted += resolver.delete(uri, where.toString(), block); + } else { + final StringBuilder where = new StringBuilder(inColumn + " IN(" + + TwidereArrayUtils.toString(block, ',', true) + ")"); + if (!isEmpty(extraWhere)) { + where.append("AND ").append(extraWhere); + } + rows_deleted += resolver.delete(uri, where.toString(), null); + } + } + return rows_deleted; + } + + public static int bulkInsert(final ContentResolver resolver, final Uri uri, final Collection values) { + if (values == null) return 0; + return bulkInsert(resolver, uri, values.toArray(new ContentValues[values.size()])); + } + + public static int bulkInsert(final ContentResolver resolver, final Uri uri, final ContentValues[] values) { + if (resolver == null || uri == null || values == null || values.length == 0) return 0; + final int colValuesLength = values.length, blocksCount = colValuesLength / MAX_BULK_COUNT + 1; + int rowsInserted = 0; + for (int i = 0; i < blocksCount; i++) { + final int start = i * MAX_BULK_COUNT, end = Math.min(start + MAX_BULK_COUNT, colValuesLength); + final ContentValues[] block = new ContentValues[end - start]; + System.arraycopy(values, start, block, 0, end - start); + rowsInserted += resolver.bulkInsert(uri, block); + } + return rowsInserted; + } + + public static Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection, + final String selection, final String[] selectionArgs, final String sortOrder) { + return resolver.query(uri, projection, selection, selectionArgs, sortOrder); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public static Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection, + final String selection, final String[] selectionArgs, final String sortOrder, + final CancellationSignal cancellationSignal) { + return resolver.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); + } + +} diff --git a/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/content/ContentValuesUtils.java b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/content/ContentValuesUtils.java new file mode 100644 index 00000000..ad279e8b --- /dev/null +++ b/firetweet.component.common/src/main/java/org/getlantern/firetweet/util/content/ContentValuesUtils.java @@ -0,0 +1,46 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.util.content; + +import android.content.ContentValues; + +public class ContentValuesUtils { + + public static boolean getAsBoolean(final ContentValues values, final String key, final boolean def) { + if (values == null || key == null) return def; + final Object value = values.get(key); + if (value == null) return def; + return Boolean.valueOf(value.toString()); + } + + public static long getAsInteger(final ContentValues values, final String key, final int def) { + if (values == null || key == null) return def; + final Object value = values.get(key); + if (value == null) return def; + return Integer.valueOf(value.toString()); + } + + public static long getAsLong(final ContentValues values, final String key, final long def) { + if (values == null || key == null) return def; + final Object value = values.get(key); + if (value == null) return def; + return Long.valueOf(value.toString()); + } +} diff --git a/firetweet.component.common/src/main/res/values/arrays.xml b/firetweet.component.common/src/main/res/values/arrays.xml new file mode 100644 index 00000000..3f73f280 --- /dev/null +++ b/firetweet.component.common/src/main/res/values/arrays.xml @@ -0,0 +1,37 @@ + + + + + + + + 6ce85096 + + deffe9c7 + + 9f00e0cb + + df27640e + + 62bd0d33 + + 56d8f9ff + + diff --git a/firetweet.component.common/src/main/res/values/defaults.xml b/firetweet.component.common/src/main/res/values/defaults.xml new file mode 100644 index 00000000..7bdeea29 --- /dev/null +++ b/firetweet.component.common/src/main/res/values/defaults.xml @@ -0,0 +1,23 @@ + + + + + 15 + diff --git a/firetweet.component.jsonserializer/.gitignore b/firetweet.component.jsonserializer/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.component.jsonserializer/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.component.jsonserializer/build.gradle b/firetweet.component.jsonserializer/build.gradle new file mode 100644 index 00000000..7ade2159 --- /dev/null +++ b/firetweet.component.jsonserializer/build.gradle @@ -0,0 +1,40 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.component.jsonserializer/proguard-rules.pro b/firetweet.component.jsonserializer/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.component.jsonserializer/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.component.jsonserializer/src/androidTest/java/org/getlantern/jsonserializer/ApplicationTest.java b/firetweet.component.jsonserializer/src/androidTest/java/org/getlantern/jsonserializer/ApplicationTest.java new file mode 100644 index 00000000..3329bde3 --- /dev/null +++ b/firetweet.component.jsonserializer/src/androidTest/java/org/getlantern/jsonserializer/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.jsonserializer; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.component.jsonserializer/src/main/AndroidManifest.xml b/firetweet.component.jsonserializer/src/main/AndroidManifest.xml new file mode 100644 index 00000000..90724425 --- /dev/null +++ b/firetweet.component.jsonserializer/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + diff --git a/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONArrayParcel.java b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONArrayParcel.java new file mode 100644 index 00000000..b4508616 --- /dev/null +++ b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONArrayParcel.java @@ -0,0 +1,50 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.jsonserializer; + +import org.json.JSONArray; +import org.getlantern.jsonserializer.JSONParcelable.Creator; + +/** + * Created by mariotaku on 15/1/1. + */ +public final class JSONArrayParcel { + + private final JSONArray jsonArray; + + JSONArrayParcel(JSONArray json) { + if (json == null) throw new NullPointerException(); + jsonArray = json; + } + + public String readString(int index) { + return jsonArray.optString(index); + } + + public T readParcelable(int index, Creator creator) { + final JSONParcel parcel = new JSONParcel(jsonArray.optJSONObject(index)); + return creator.createFromParcel(parcel); + } + + + public int size() { + return jsonArray.length(); + } +} diff --git a/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONParcel.java b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONParcel.java new file mode 100644 index 00000000..1f46ce85 --- /dev/null +++ b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONParcel.java @@ -0,0 +1,377 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.jsonserializer; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; + +public final class JSONParcel { + + private final JSONObject jsonObject; + + JSONParcel() { + this(new JSONObject()); + } + + JSONParcel(final JSONObject json) { + if (json == null) throw new NullPointerException(); + jsonObject = json; + } + + public boolean contains(final String key) { + return jsonObject.has(key); + } + + public JSONObject getJSON() { + return jsonObject; + } + + public boolean isNull(String key) { + return jsonObject.isNull(key); + } + + public boolean readBoolean(final String key) { + return jsonObject.optBoolean(key); + } + + public boolean readBoolean(final String key, final boolean def) { + return jsonObject.optBoolean(key, def); + } + + public double readDouble(final String key) { + return jsonObject.optDouble(key); + } + + public double readDouble(final String key, final double def) { + return jsonObject.optDouble(key, def); + } + + public float readFloat(final String key, final float def) { + return (float) readDouble(key, def); + } + + public int readInt(final String key) { + return jsonObject.optInt(key); + } + + public int readInt(final String key, final int def) { + return jsonObject.optInt(key, def); + } + + public JSONObject readJSONObject(final String key) { + return jsonObject.optJSONObject(key); + } + + public JSONArray readJSONArray(final String key) { + return jsonObject.optJSONArray(key); + } + + public JSONArrayParcel readJSONArrayParcel(final String key) { + if (jsonObject.isNull(key)) return null; + return new JSONArrayParcel(readJSONArray(key)); + } + + public String[] readStringArray(final String key) { + if (jsonObject.isNull(key)) return null; + final JSONArray array = jsonObject.optJSONArray(key); + final String[] stringArray = new String[array.length()]; + for (int i = 0, j = array.length(); i < j; i++) { + try { + stringArray[i] = array.getString(i); + } catch (JSONException e) { + return null; + } + } + return stringArray; + } + + public long readLong(final String key) { + return jsonObject.optLong(key); + } + + public long readLong(final String key, final long def) { + return jsonObject.optLong(key, def); + } + + public Object readObject(final String key) { + return jsonObject.opt(key); + } + + public T readParcelable(final String key, final JSONParcelable.Creator creator) { + return JSONSerializer.createObject(creator, jsonObject.optJSONObject(key)); + } + + public T[] readParcelableArray(final String key, final JSONParcelable.Creator creator) { + return JSONSerializer.createArray(creator, jsonObject.optJSONArray(key)); + } + + public String readString(final String key) { + return readString(key, null); + } + + public String readString(final String key, final String def) { + return jsonObject.optString(key, def); + } + + public void writeBoolean(final String key, final boolean value) { + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeBooleanArray(final String key, final boolean[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final boolean item : value) { + array.put(item); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeDouble(final String key, final double value) { + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeDoubleArray(final String key, final double[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final double item : value) { + array.put(item); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeFloat(final String key, final float value) { + writeDouble(key, value); + } + + public void writeFloatArray(final String key, final float[] value) { + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final float item : value) { + array.put(item); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeInt(final String key, final int value) { + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeIntArray(final String key, final int[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final int item : value) { + array.put(item); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeJSONArray(final String key, final JSONArray value) { + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeJSONObject(final String key, final JSONObject value) { + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeLong(final String key, final long value) { + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeLongArray(final String key, final long[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final long item : value) { + array.put(item); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeObject(final String key, final Object value) { + if (value instanceof JSONParcelable) { + writeParcelable(key, (JSONParcelable) value); + return; + } + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeObjectArray(final String key, final Object[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final Object item : value) { + if (item instanceof JSONParcelable) { + final JSONObject json = JSONSerializer.toJSONObject((JSONParcelable) item); + array.put(json); + } else { + array.put(item); + } + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeObjectList(final String key, final List value) { + if (key == null) return; + writeObjectArray(key, value.toArray()); + } + + public void writeParcelable(final String key, final T value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONObject json = JSONSerializer.toJSONObject(value); + jsonObject.put(key, json); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeParcelableArray(final String key, final T[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final T item : value) { + final JSONObject json = JSONSerializer.toJSONObject(item); + array.put(json != null ? json : JSONObject.NULL); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeString(final String key, final String value) { + if (key == null) return; + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeStringArray(final String key, final String[] value) { + if (key == null) return; + try { + if (value == null) { + jsonObject.put(key, JSONObject.NULL); + return; + } + final JSONArray array = new JSONArray(); + for (final String item : value) { + array.put(item); + } + jsonObject.put(key, array); + } catch (final JSONException e) { + e.printStackTrace(); + } + } + + public void writeValue(final String key, final Object value) { + if (key == null) return; + try { + jsonObject.put(key, value); + } catch (final JSONException e) { + e.printStackTrace(); + } + } +} diff --git a/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONParcelable.java b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONParcelable.java new file mode 100644 index 00000000..4e2cf953 --- /dev/null +++ b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONParcelable.java @@ -0,0 +1,40 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.jsonserializer; + +public interface JSONParcelable { + + public void writeToParcel(JSONParcel out); + + public interface Creator { + + public T createFromParcel(JSONParcel in); + + public T[] newArray(int size); + } +} diff --git a/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONSerializer.java b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONSerializer.java new file mode 100644 index 00000000..d2dd26d8 --- /dev/null +++ b/firetweet.component.jsonserializer/src/main/java/org/getlantern/jsonserializer/JSONSerializer.java @@ -0,0 +1,148 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.jsonserializer; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; + +public class JSONSerializer { + private static boolean debugMode = false; + + public static T[] createArray(final JSONParcelable.Creator creator, + final JSONArray json) { + if (creator == null) throw new NullPointerException("JSON_CREATOR must not be null!"); + if (json == null) return null; + final int size = json.length(); + final T[] array = creator.newArray(size); + for (int i = 0; i < size; i++) { + array[i] = creator.createFromParcel(new JSONParcel(json.optJSONObject(i))); + } + return array; + } + + public static ArrayList createArrayList(final JSONParcelable.Creator creator, + final JSONArray json) { + if (creator == null) throw new NullPointerException("JSON_CREATOR must not be null!"); + if (json == null) return null; + final int size = json.length(); + final ArrayList list = new ArrayList(size); + for (int i = 0; i < size; i++) { + list.add(creator.createFromParcel(new JSONParcel(json.optJSONObject(i)))); + } + return list; + } + + public static T createObject(final JSONParcelable.Creator creator, + final JSONObject json) { + if (creator == null) throw new NullPointerException("JSON_CREATOR must not be null!"); + if (json == null) return null; + return creator.createFromParcel(new JSONParcel(json)); + } + + public static byte[] getByteArray(final T parcelable) { + final JSONObject json = toJSONObject(parcelable); + final String string = jsonToString(json); + if (string == null) return null; + return string.getBytes(Charset.defaultCharset()); + } + + public static byte[] getByteArray(final T[] array) { + final JSONArray json = toJSONArray(array); + final String string = jsonToString(json); + if (string == null) return null; + return string.getBytes(Charset.defaultCharset()); + } + + public static boolean isDebugMode() { + return debugMode; + } + + public static void setIsDebugMode(final boolean debug) { + debugMode = debug; + } + + public static byte[] toByteArray(final T parcelable) throws IOException { + final String jsonString = jsonToString(toJSONObject(parcelable)); + if (jsonString == null) return null; + return jsonString.getBytes(Charset.defaultCharset()); + } + + public static byte[] toByteArray(final T[] array) throws IOException { + final String jsonString = jsonToString(toJSONArray(array)); + if (jsonString == null) return null; + return jsonString.getBytes(Charset.defaultCharset()); + } + + public static JSONArray toJSONArray(final T[] array) { + if (array == null) return null; + final JSONArray json = new JSONArray(); + for (final T parcelable : array) { + json.put(toJSONObject(parcelable)); + } + return json; + } + + public static String toJSONArrayString(final T[] array) { + return jsonToString(toJSONArray(array)); + } + + public static JSONObject toJSONObject(final T parcelable) { + if (parcelable == null) return null; + final JSONObject json = new JSONObject(); + parcelable.writeToParcel(new JSONParcel(json)); + return json; + } + + public static String toJSONObjectString(final T parcelable) { + return jsonToString(toJSONObject(parcelable)); + } + + static String jsonToString(final JSONArray json) { + if (json == null) return null; + if (debugMode) { + try { + return json.toString(4); + } catch (final JSONException e) { + e.printStackTrace(); + } + return json.toString(); + } else + return json.toString(); + } + + static String jsonToString(final JSONObject json) { + if (json == null) return null; + if (debugMode) { + try { + return json.toString(4); + } catch (final JSONException e) { + e.printStackTrace(); + } + return json.toString(); + } else + return json.toString(); + } + +} diff --git a/firetweet.component.nyan/.gitignore b/firetweet.component.nyan/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.component.nyan/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.component.nyan/build.gradle b/firetweet.component.nyan/build.gradle new file mode 100644 index 00000000..a166550a --- /dev/null +++ b/firetweet.component.nyan/build.gradle @@ -0,0 +1,40 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.component.nyan/proguard-rules.pro b/firetweet.component.nyan/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.component.nyan/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.component.nyan/src/androidTest/java/org/getlantern/firetweet/nyan/ApplicationTest.java b/firetweet.component.nyan/src/androidTest/java/org/getlantern/firetweet/nyan/ApplicationTest.java new file mode 100644 index 00000000..482def50 --- /dev/null +++ b/firetweet.component.nyan/src/androidTest/java/org/getlantern/firetweet/nyan/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.component.nyan/src/main/AndroidManifest.xml b/firetweet.component.nyan/src/main/AndroidManifest.xml new file mode 100644 index 00000000..6f499374 --- /dev/null +++ b/firetweet.component.nyan/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanConstants.java b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanConstants.java new file mode 100644 index 00000000..f94be682 --- /dev/null +++ b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanConstants.java @@ -0,0 +1,30 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +/** + * Created by mariotaku on 14/12/19. + */ +public interface NyanConstants { + + public static final String SHARED_PREFERENCES_NAME = "nyan_preferences"; + + public static final String KEY_LIVE_WALLPAPER_SCALE = "live_wallpaper_scale"; +} diff --git a/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDaydreamService.java b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDaydreamService.java new file mode 100644 index 00000000..5946b885 --- /dev/null +++ b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDaydreamService.java @@ -0,0 +1,83 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +import android.annotation.TargetApi; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.res.Resources; +import android.os.Build; +import android.service.dreams.DreamService; +import android.view.View; +import android.view.View.OnSystemUiVisibilityChangeListener; + +@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) +public class NyanDaydreamService extends DreamService implements NyanConstants, + OnSharedPreferenceChangeListener, OnSystemUiVisibilityChangeListener { + + private NyanDaydreamView mNyanDaydreamView; + private SharedPreferences mPreferences; + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + setContentView(R.layout.nyan_daydream); + mNyanDaydreamView.setOnSystemUiVisibilityChangeListener(this); + updateView(); + } + + @Override + public void onContentChanged() { + super.onContentChanged(); + mNyanDaydreamView = (NyanDaydreamView) findViewById(R.id.nyan); + } + + @Override + public void onCreate() { + super.onCreate(); + mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE); + mPreferences.registerOnSharedPreferenceChangeListener(this); + setInteractive(false); + setFullscreen(true); + setScreenBright(false); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { + if (KEY_LIVE_WALLPAPER_SCALE.equals(key)) { + updateView(); + } + } + + @Override + public void onSystemUiVisibilityChange(final int visibility) { + if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { + finish(); + } + } + + private void updateView() { + if (mPreferences == null) return; + final Resources res = getResources(); + final int def = res.getInteger(R.integer.default_live_wallpaper_scale); + mNyanDaydreamView.setScale(mPreferences.getInt(KEY_LIVE_WALLPAPER_SCALE, def)); + } + +} diff --git a/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDaydreamView.java b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDaydreamView.java new file mode 100644 index 00000000..e5d84988 --- /dev/null +++ b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDaydreamView.java @@ -0,0 +1,116 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.View; + +public class NyanDaydreamView extends View { + + private final InvalidateRunnable mInvalidateRunnable; + + private final NyanDrawingHelper mNyanDrawingHelper; + + public NyanDaydreamView(final Context context) { + this(context, null); + } + + public NyanDaydreamView(final Context context, final AttributeSet attrs) { + this(context, attrs, 0); + } + + public NyanDaydreamView(final Context context, final AttributeSet attrs, final int defStyleAttr) { + super(context, attrs, defStyleAttr); + setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + mNyanDrawingHelper = new DreamViewNyanDrawingHelper(this); + mInvalidateRunnable = new InvalidateRunnable(this); + } + + public void setScale(final float scale) { + mNyanDrawingHelper.setScale(scale); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + post(mInvalidateRunnable); + } + + @Override + protected void onDetachedFromWindow() { + removeCallbacks(mInvalidateRunnable); + super.onDetachedFromWindow(); + } + + @Override + protected void onDraw(final Canvas canvas) { + super.onDraw(canvas); + mNyanDrawingHelper.dispatchDraw(canvas); + } + + @Override + protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mNyanDrawingHelper.dispatchSizeChanged(w, h); + } + + private static final class DreamViewNyanDrawingHelper extends NyanDrawingHelper { + + private final int mDisplayHeight; + private final NyanDaydreamView mView; + + public DreamViewNyanDrawingHelper(final NyanDaydreamView view) { + super(view.getContext()); + mView = view; + final Resources res = getResources(); + final DisplayMetrics dm = res.getDisplayMetrics(); + mDisplayHeight = dm.heightPixels; + } + + @Override + protected int getRainbowYOffset() { + final int visibility = mView.getSystemUiVisibility(); + if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) return 0; + return mDisplayHeight - getHeight(); + } + + } + + private static final class InvalidateRunnable implements Runnable { + + private final View mView; + + InvalidateRunnable(final View view) { + mView = view; + } + + @Override + public void run() { + mView.invalidate(); + mView.postDelayed(this, 66); + } + + } + +} diff --git a/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDrawingHelper.java b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDrawingHelper.java new file mode 100644 index 00000000..676de699 --- /dev/null +++ b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanDrawingHelper.java @@ -0,0 +1,598 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Shader.TileMode; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Random; + +public class NyanDrawingHelper { + + private static final float SAKAMOTO_DOT_SIZE = 6; + private static final float RAINBOW_DOT_SIZE = 3; + private static final float STARS_DOT_SIZE = 4; + + private final StarsDrawingHelper mStarsHelper; + private final DrawableDrawingHelper mRainbowHelper, mSakamotoHelper; + private final IDrawingHelper[] mDrawingHelpers; + private final int mBackgroundColor; + private final Resources mResources; + private final float mDensity; + + private float mScale; + private int mWidth, mHeight; + + private static final int[] RAINBOW_FRAMES = {R.drawable.nyan_rainbow_frame00_tile, + R.drawable.nyan_rainbow_frame01_tile, R.drawable.nyan_rainbow_frame02_tile, + R.drawable.nyan_rainbow_frame03_tile, R.drawable.nyan_rainbow_frame04_tile, + R.drawable.nyan_rainbow_frame05_tile, R.drawable.nyan_rainbow_frame06_tile, + R.drawable.nyan_rainbow_frame07_tile, R.drawable.nyan_rainbow_frame08_tile, + R.drawable.nyan_rainbow_frame09_tile, R.drawable.nyan_rainbow_frame10_tile, + R.drawable.nyan_rainbow_frame11_tile}; + + public NyanDrawingHelper(final Context context) { + mResources = context.getResources(); + mDensity = mResources.getDisplayMetrics().density; + final int starRows = mResources.getInteger(R.integer.nyan_star_rows); + final int starCols = mResources.getInteger(R.integer.nyan_star_cols); + final int starDotSize = Math.round(STARS_DOT_SIZE * mDensity); + mStarsHelper = new StarsDrawingHelper(starRows, starCols, starDotSize, Color.WHITE); + mRainbowHelper = new DrawableDrawingHelper(); + final Calendar cal = Calendar.getInstance(); + final int sakamotoRes; + if (cal.get(Calendar.MONTH) == Calendar.DECEMBER) { + sakamotoRes = R.drawable.nyan_sakamoto_santa; + } else { + sakamotoRes = R.drawable.nyan_sakamoto; + } + mSakamotoHelper = new DrawableDrawingHelper(mResources.getDrawable(sakamotoRes)); + mDrawingHelpers = new IDrawingHelper[]{mStarsHelper, mRainbowHelper, mSakamotoHelper}; + mBackgroundColor = mResources.getColor(R.color.nyan_background); + } + + public final void dispatchDraw(final Canvas canvas) { + if (canvas == null) return; + canvas.drawColor(mBackgroundColor); + for (final IDrawingHelper h : mDrawingHelpers) { + h.dispatchOnDraw(canvas); + } + } + + public final void dispatchSizeChanged(final int width, final int height) { + mWidth = width; + mHeight = height; + for (final IDrawingHelper h : mDrawingHelpers) { + h.dispatchSizeChanged(width, height); + } + setupSpirtes(); + } + + public final float getDensity() { + return mDensity; + } + + public final int getHeight() { + return mHeight; + } + + public final Resources getResources() { + return mResources; + } + + public final float getScale() { + return mScale; + } + + public final int getWidth() { + return mWidth; + } + + public final void setScale(final float scale) { + mScale = scale; + mRainbowHelper.setDrawable(createRainbowDrawable(scale)); + mStarsHelper.setDotScale(scale); + setupSpirtes(); + } + + protected int getRainbowYOffset() { + return 0; + } + + private Drawable createRainbowDrawable(final float scale) { + final AnimationDrawable ad = new AnimationDrawable(); + ad.setOneShot(false); + final int rainbowDotScale = Math.round(RAINBOW_DOT_SIZE * mDensity * scale); + for (final int frameRes : RAINBOW_FRAMES) { + final Bitmap b = BitmapFactory.decodeResource(mResources, frameRes); + if (b == null) { + continue; + } + final int w = b.getWidth(), h = b.getHeight(); + final int sw = w * rainbowDotScale, sh = h * rainbowDotScale; + final BitmapDrawable bd; + if (w != sw || h != sh) { + final Bitmap sb = Bitmap.createScaledBitmap(b, sw, sh, false); + b.recycle(); + bd = new TileBitmapDrawable(mResources, sb); + } else { + bd = new TileBitmapDrawable(mResources, b); + } + bd.setTileModeX(TileMode.REPEAT); + bd.setTileModeY(TileMode.REPEAT); + ad.addFrame(bd, 70); + } + return ad; + } + + private void setupSpirtes() { + final int width = mWidth, height = mHeight; + if (width == 0 || height == 0) return; + final int centerX = width / 2, centerY = height / 2; + final int sakamotoDotScale = Math.round(SAKAMOTO_DOT_SIZE * mDensity * mScale); + final int sakamotoW = mSakamotoHelper.getIntrinsicWidth() * sakamotoDotScale; + final int sakamotoH = mSakamotoHelper.getIntrinsicHeight() * sakamotoDotScale; + final int sakamotoLeft = centerX - sakamotoW / 2, sakamotoTop = centerY - sakamotoH / 2; + mSakamotoHelper.setBounds(sakamotoLeft, sakamotoTop, sakamotoLeft + sakamotoW, sakamotoTop + sakamotoH); + final int rainbowH = mRainbowHelper.getIntrinsicHeight(); + final int rainbowTop = sakamotoTop + sakamotoH / 2 + getRainbowYOffset(); + mRainbowHelper.setBounds(0, rainbowTop, centerX - sakamotoW / 4, rainbowTop + rainbowH); + } + + public static final class DrawableDrawingHelper implements IDrawingHelper { + + private Drawable mDrawable; + private int mAnimationFrames; + private int mCurrentFrame = 0; + + DrawableDrawingHelper() { + this(null); + } + + DrawableDrawingHelper(final Drawable drawable) { + setDrawable(drawable); + } + + + @Override + public void dispatchOnDraw(final Canvas canvas) { + if (mDrawable == null) return; + if (mAnimationFrames > 0) { + final AnimationDrawable ad = (AnimationDrawable) mDrawable; + final Drawable frame = ad.getFrame(mCurrentFrame++); + frame.draw(canvas); + if (mCurrentFrame >= mAnimationFrames) { + mCurrentFrame = 0; + } + } else { + mDrawable.draw(canvas); + } + } + + @Override + public void dispatchSizeChanged(final int w, final int h) { + } + + public Drawable getDrawable() { + return mDrawable; + } + + public int getIntrinsicHeight() { + return mDrawable != null ? mDrawable.getIntrinsicHeight() : -1; + } + + public int getIntrinsicWidth() { + return mDrawable != null ? mDrawable.getIntrinsicWidth() : -1; + } + + public int getMinimumHeight() { + return mDrawable != null ? mDrawable.getMinimumHeight() : -1; + } + + public int getMinimumWidth() { + return mDrawable != null ? mDrawable.getMinimumWidth() : -1; + } + + public void setBounds(final int left, final int top, final int right, final int bottom) { + if (mDrawable == null) return; + if (mAnimationFrames > 0) { + mDrawable.setBounds(left, top, right, bottom); + for (int i = 0; i < mAnimationFrames; i++) { + final Drawable frame = ((AnimationDrawable) mDrawable).getFrame(i); + frame.setBounds(left, top, right, bottom); + } + } else { + mDrawable.setBounds(left, top, right, bottom); + } + } + + public void setDrawable(final Drawable drawable) { + mDrawable = drawable; + if (drawable instanceof AnimationDrawable) { + mAnimationFrames = ((AnimationDrawable) drawable).getNumberOfFrames(); + } else { + mAnimationFrames = -1; + } + } + + } + + public static interface IDrawingHelper { + public void dispatchOnDraw(final Canvas canvas); + + public void dispatchSizeChanged(final int w, final int h); + } + + public static final class TileBitmapDrawable extends BitmapDrawable { + private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); + private final Matrix mMatrix = new Matrix(); + + private boolean mRebuildShader = true; + + public TileBitmapDrawable(final Resources res, final Bitmap bitmap) { + super(res, bitmap); + } + + @Override + public void draw(final Canvas canvas) { + final Bitmap bitmap = getBitmap(); + if (bitmap == null) return; + + if (mRebuildShader) { + mPaint.setShader(new BitmapShader(bitmap, getTileMode(getTileModeX()), getTileMode(getTileModeY()))); + mRebuildShader = false; + } + + final Rect bounds = getBounds(); + // Translate down by the remainder + mMatrix.setTranslate(bounds.left, bounds.top); + canvas.save(); + canvas.setMatrix(mMatrix); + canvas.drawRect(0, 0, bounds.width(), bounds.height(), mPaint); + canvas.restore(); + } + + private static TileMode getTileMode(final TileMode mode) { + return mode != null ? mode : TileMode.CLAMP; + } + } + + private static final class StarsDrawingHelper implements IDrawingHelper { + + private final int mStarRows, mStarCols, mStarDotSize; + + private final Paint mPaint; + + private final ArrayList mStars = new ArrayList(); + + private final Random mRandom = new Random(); + + private float mDotScale; + + public StarsDrawingHelper(final int starRows, final int starCols, final int starDotSize, final int starColor) { + mStarRows = starRows; + mStarCols = starCols; + mStarDotSize = starDotSize; + mPaint = new Paint(); + mPaint.setColor(starColor); + setDotScale(1.0f); + } + + @Override + public void dispatchOnDraw(final Canvas canvas) { + final int w = canvas.getWidth(), h = canvas.getHeight(); + if (w <= 0 || h <= 0) return; + for (final Star star : mStars.toArray(new Star[mStars.size()])) { + final int col = star.nextColumn(), row = star.nextRow(); + final float y = (row + 0.5f) * (h / mStarRows), x = (col + 0.5f) * (w / mStarCols); + drawStar(canvas, x, y, star.nextFrame()); + } + } + + @Override + public void dispatchSizeChanged(final int w, final int h) { + mStars.clear(); + if (w <= 0 || h <= 0) return; + for (int i = 0; i < mStarRows; i++) { + final int frame = mRandom.nextInt(7); + final int col = mRandom.nextInt(mStarCols); + final Star star; + if (mRandom.nextBoolean()) { + star = new Star1(frame, col, i, mStarCols, mStarRows); + } else { + star = new Star2(frame, col, i, mStarCols, mStarRows); + } + mStars.add(star); + } + } + + public void setDotScale(final float scale) { + mDotScale = scale; + } + + private void drawStar(final Canvas canvas, final float x, final float y, final byte[][] frame) { + final int rows = frame.length; + final int starDotSize = Math.round(mDotScale * mStarDotSize); + for (int row = 0; row < rows; row++) { + final int cols = frame[row].length; + final float top = y + starDotSize * row - starDotSize * rows / 2; + for (int col = 0; col < cols; col++) { + final byte point = frame[row][col]; + if (point != 0) { + final float left = x + starDotSize * col - starDotSize * cols / 2; + canvas.drawRect(left, top, left + starDotSize, top + starDotSize, mPaint); + } + } + } + } + + private static abstract class Star implements StarAnimFrames { + + private final int mMaxColumn, mMaxRow; + private int mCurrentFrame, mCurrentColumn, mCurrentRow; + + Star(final int initialFrame, final int initialColumn, final int initialRow, final int maxColumn, + final int maxRow) { + setFrame(initialFrame); + mMaxColumn = maxColumn; + mMaxRow = maxRow; + setColumn(initialColumn); + setRow(initialRow); + } + + public abstract byte[][][] getFrames(); + + public final int length() { + return getFrames().length; + } + + public final int nextColumn() { + final int column = mCurrentColumn; + mCurrentColumn--; + if (mCurrentColumn < 0) { + mCurrentColumn = mMaxColumn - 1; + } + return column; + } + + public final byte[][] nextFrame() { + final byte[][] frame = getFrames()[mCurrentFrame]; + mCurrentFrame++; + if (mCurrentFrame >= length()) { + mCurrentFrame = 0; + } + return frame; + } + + public final int nextRow() { + return mCurrentRow; + } + + public void setColumn(final int column) { + if (column < 0 || column >= mMaxColumn) { + mCurrentColumn = 0; + } else { + mCurrentColumn = column; + } + } + + public void setFrame(final int frame) { + if (frame < 0 || frame >= length()) { + mCurrentFrame = 0; + } else { + mCurrentFrame = frame; + } + } + + public void setRow(final int row) { + if (row < 0 || row >= mMaxRow) { + mCurrentRow = 0; + } else { + mCurrentRow = row; + } + } + } + + private static final class Star1 extends Star { + + private static final byte[][][] FRAMES = new byte[][][]{FRAME1, FRAME2, FRAME3, FRAME4, FRAME5, FRAME6}; + + public Star1(final int initialFrame, final int initialColumn, final int initialRow, final int maxColumn, + final int maxRow) { + super(initialFrame, initialColumn, initialRow, maxColumn, maxRow); + } + + @Override + public byte[][][] getFrames() { + return FRAMES; + } + } + + private static final class Star2 extends Star { + private static final byte[][][] FRAMES = new byte[][][]{FRAME1, FRAME6, FRAME5, FRAME4, FRAME3, FRAME2}; + + public Star2(final int initialFrame, final int initialColumn, final int initialRow, final int maxColumn, + final int maxRow) { + super(initialFrame, initialColumn, initialRow, maxColumn, maxRow); + } + + @Override + public byte[][][] getFrames() { + return FRAMES; + } + } + + private static interface StarAnimFrames { + static final byte[][] FRAME1 = { + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + } + }; + static final byte[][] FRAME2 = { + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 1, 0, 1, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + } + }; + static final byte[][] FRAME3 = { + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 1, 1, 0, 1, 1, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + } + }; + static final byte[][] FRAME4 = { + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 1, 1, 0, 1, 0, 1, 1 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + } + }; + static final byte[][] FRAME5 = { + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 1, 0, 0, 0, 1, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 1, 0, 0, 0, 0, 0, 1 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 1, 0, 0, 0, 1, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + } + }; + static final byte[][] FRAME6 = { + { + 0, 0, 0, 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 1, 0, 0, 0, 0, 0, 1 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 1, 0, 0, 0 + } + }; + + } + } +} diff --git a/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanSurfaceHelper.java b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanSurfaceHelper.java new file mode 100644 index 00000000..792644af --- /dev/null +++ b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanSurfaceHelper.java @@ -0,0 +1,126 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +import android.content.Context; +import android.graphics.Canvas; +import android.view.SurfaceHolder; + +public final class NyanSurfaceHelper implements SurfaceHolder.Callback { + + private SurfaceHolder mHolder; + private DrawingThread mThread; + private final NyanDrawingHelper mNyanDrawingHelper; + + public NyanSurfaceHelper(final Context context) { + mNyanDrawingHelper = new NyanDrawingHelper(context); + } + + public SurfaceHolder getHolder() { + return mHolder; + } + + public void setScale(final float scale) { + mNyanDrawingHelper.setScale(scale); + } + + public void setSkipDrawing(final boolean skipDrawing) { + if (mThread != null) { + mThread.setSkipDrawing(skipDrawing); + } + } + + public void start() { + if (mThread != null) return; + mThread = new DrawingThread(this, mNyanDrawingHelper); + mThread.start(); + } + + public void stop() { + if (mThread != null) { + mThread.cancel(); + } + mThread = null; + } + + @Override + public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) { + mNyanDrawingHelper.dispatchSizeChanged(width, height); + } + + @Override + public void surfaceCreated(final SurfaceHolder holder) { + mHolder = holder; + start(); + } + + @Override + public void surfaceDestroyed(final SurfaceHolder holder) { + stop(); + mHolder = null; + } + + private static class DrawingThread extends Thread { + + private final NyanSurfaceHelper mSurfaceHelper; + private final NyanDrawingHelper mDrawingHelper; + private boolean mCancelled; + private boolean mSkipDrawing; + + DrawingThread(final NyanSurfaceHelper surfaceHelper, final NyanDrawingHelper drawingHelper) { + mSurfaceHelper = surfaceHelper; + mDrawingHelper = drawingHelper; + } + + public void cancel() { + mCancelled = true; + } + + @Override + public void run() { + while (!mCancelled) { + final long startTime = System.currentTimeMillis(); + drawFrame(); + final long endTime = System.currentTimeMillis(); + try { + Thread.sleep(Math.max(0, 66 - (endTime - startTime))); + } catch (final InterruptedException ignored) { + + } + } + } + + public void setSkipDrawing(final boolean skipDrawing) { + mSkipDrawing = skipDrawing; + } + + private void drawFrame() { + final SurfaceHolder holder = mSurfaceHelper.getHolder(); + if (mSkipDrawing || holder == null || holder.isCreating()) return; + final Canvas c = holder.lockCanvas(); + if (c == null) return; + if (mDrawingHelper != null) { + mDrawingHelper.dispatchDraw(c); + } + holder.unlockCanvasAndPost(c); + } + + } +} diff --git a/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanWallpaperService.java b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanWallpaperService.java new file mode 100644 index 00000000..ab4201c0 --- /dev/null +++ b/firetweet.component.nyan/src/main/java/org/getlantern/firetweet/nyan/NyanWallpaperService.java @@ -0,0 +1,133 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.nyan; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.res.Resources; +import android.os.PowerManager; +import android.service.wallpaper.WallpaperService; +import android.view.SurfaceHolder; + +public class NyanWallpaperService extends WallpaperService implements NyanConstants { + + @Override + public Engine onCreateEngine() { + return new NyanWallpaperEngine(); + } + + private Context getContext() { + return this; + } + + private final class NyanWallpaperEngine extends Engine implements OnSharedPreferenceChangeListener { + + private SharedPreferences mPreferences; + private final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + if (Intent.ACTION_SCREEN_ON.equals(action)) { + if (mHelper == null) return; + mHelper.start(); + } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { + if (mHelper == null) return; + mHelper.stop(); + } + + } + }; + + private NyanSurfaceHelper mHelper; + + @Override + public void onCreate(final SurfaceHolder surfaceHolder) { + super.onCreate(surfaceHolder); + mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE); + mPreferences.registerOnSharedPreferenceChangeListener(this); + mHelper = new NyanSurfaceHelper(getContext()); + final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(mScreenReceiver, filter); + } + + @Override + public void onDestroy() { + mPreferences.unregisterOnSharedPreferenceChangeListener(this); + unregisterReceiver(mScreenReceiver); + super.onDestroy(); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { + if (KEY_LIVE_WALLPAPER_SCALE.equals(key)) { + updateSurface(); + } + } + + @Override + public void onSurfaceCreated(final SurfaceHolder holder) { + super.onSurfaceCreated(holder); + holder.addCallback(mHelper); + updateSurface(); + updateHelperState(); + } + + @Override + public void onSurfaceDestroyed(final SurfaceHolder holder) { + mHelper.stop(); + holder.removeCallback(mHelper); + super.onSurfaceDestroyed(holder); + } + + @Override + public void onVisibilityChanged(final boolean visible) { + super.onVisibilityChanged(visible); + if (mHelper != null) { + mHelper.setSkipDrawing(!visible); + } + } + + private void updateHelperState() { + final PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); + if (pm.isScreenOn()) { + mHelper.start(); + } else { + mHelper.stop(); + } + } + + private void updateSurface() { + if (mPreferences == null) return; + final Resources res = getResources(); + final int def = res.getInteger(R.integer.default_live_wallpaper_scale); + mHelper.setScale(mPreferences.getInt(KEY_LIVE_WALLPAPER_SCALE, def)); + updateHelperState(); + } + + } + +} diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame00_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame00_tile.png new file mode 100644 index 00000000..b17da515 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame00_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame01_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame01_tile.png new file mode 100644 index 00000000..dfa116e5 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame01_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame02_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame02_tile.png new file mode 100644 index 00000000..b541ec4d Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame02_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame03_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame03_tile.png new file mode 100644 index 00000000..b11af308 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame03_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame04_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame04_tile.png new file mode 100644 index 00000000..88e5598f Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame04_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame05_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame05_tile.png new file mode 100644 index 00000000..bb4e85c8 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame05_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame06_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame06_tile.png new file mode 100644 index 00000000..0c2f810b Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame06_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame07_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame07_tile.png new file mode 100644 index 00000000..7af285bf Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame07_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame08_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame08_tile.png new file mode 100644 index 00000000..1c034481 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame08_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame09_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame09_tile.png new file mode 100644 index 00000000..37c5b246 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame09_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame10_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame10_tile.png new file mode 100644 index 00000000..a0853419 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame10_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame11_tile.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame11_tile.png new file mode 100644 index 00000000..1aa2e5ca Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_rainbow_frame11_tile.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame00.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame00.png new file mode 100644 index 00000000..1fcdc4b0 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame00.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame01.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame01.png new file mode 100644 index 00000000..45f7cc69 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame01.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame02.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame02.png new file mode 100644 index 00000000..b9179138 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame02.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame03.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame03.png new file mode 100644 index 00000000..c18ab508 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame03.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame04.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame04.png new file mode 100644 index 00000000..bd0a3c05 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame04.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame05.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame05.png new file mode 100644 index 00000000..47119732 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame05.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame06.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame06.png new file mode 100644 index 00000000..dd0c5bd3 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame06.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame07.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame07.png new file mode 100644 index 00000000..4530508a Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame07.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame08.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame08.png new file mode 100644 index 00000000..52bb4f48 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame08.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame09.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame09.png new file mode 100644 index 00000000..25bd4218 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame09.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame10.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame10.png new file mode 100644 index 00000000..3ae3b2b1 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame10.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame11.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame11.png new file mode 100644 index 00000000..527a34ec Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_frame11.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame00.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame00.png new file mode 100644 index 00000000..be7c9c6f Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame00.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame01.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame01.png new file mode 100644 index 00000000..010d5bb5 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame01.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame02.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame02.png new file mode 100644 index 00000000..123bf6f9 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame02.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame03.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame03.png new file mode 100644 index 00000000..cab14191 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame03.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame04.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame04.png new file mode 100644 index 00000000..8583b2c9 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame04.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame05.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame05.png new file mode 100644 index 00000000..3b634831 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame05.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame06.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame06.png new file mode 100644 index 00000000..bd4cb607 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame06.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame07.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame07.png new file mode 100644 index 00000000..58b2845a Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame07.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame08.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame08.png new file mode 100644 index 00000000..fa981477 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame08.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame09.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame09.png new file mode 100644 index 00000000..5b515658 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame09.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame10.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame10.png new file mode 100644 index 00000000..c5c2ec80 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame10.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame11.png b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame11.png new file mode 100644 index 00000000..b3930445 Binary files /dev/null and b/firetweet.component.nyan/src/main/res/drawable-nodpi/nyan_sakamoto_santa_frame11.png differ diff --git a/firetweet.component.nyan/src/main/res/drawable/nyan_sakamoto.xml b/firetweet.component.nyan/src/main/res/drawable/nyan_sakamoto.xml new file mode 100644 index 00000000..1359b34a --- /dev/null +++ b/firetweet.component.nyan/src/main/res/drawable/nyan_sakamoto.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firetweet.component.nyan/src/main/res/drawable/nyan_sakamoto_santa.xml b/firetweet.component.nyan/src/main/res/drawable/nyan_sakamoto_santa.xml new file mode 100644 index 00000000..9218ff64 --- /dev/null +++ b/firetweet.component.nyan/src/main/res/drawable/nyan_sakamoto_santa.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firetweet.component.nyan/src/main/res/layout/nyan_daydream.xml b/firetweet.component.nyan/src/main/res/layout/nyan_daydream.xml new file mode 100644 index 00000000..28c087a9 --- /dev/null +++ b/firetweet.component.nyan/src/main/res/layout/nyan_daydream.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/firetweet.component.nyan/src/main/res/values-land/integers.xml b/firetweet.component.nyan/src/main/res/values-land/integers.xml new file mode 100644 index 00000000..0ca9c819 --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values-land/integers.xml @@ -0,0 +1,6 @@ + + + 5 + 17 + + diff --git a/firetweet.component.nyan/src/main/res/values-large-land/integers.xml b/firetweet.component.nyan/src/main/res/values-large-land/integers.xml new file mode 100644 index 00000000..6898c9ba --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values-large-land/integers.xml @@ -0,0 +1,6 @@ + + + 8 + 23 + + diff --git a/firetweet.component.nyan/src/main/res/values-large/integers.xml b/firetweet.component.nyan/src/main/res/values-large/integers.xml new file mode 100644 index 00000000..51215f2c --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values-large/integers.xml @@ -0,0 +1,7 @@ + + + 10 + 13 + 2 + + diff --git a/firetweet.component.nyan/src/main/res/values-xlarge-land/integers.xml b/firetweet.component.nyan/src/main/res/values-xlarge-land/integers.xml new file mode 100644 index 00000000..aed0b506 --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values-xlarge-land/integers.xml @@ -0,0 +1,6 @@ + + + 13 + 31 + + diff --git a/firetweet.component.nyan/src/main/res/values-xlarge/integers.xml b/firetweet.component.nyan/src/main/res/values-xlarge/integers.xml new file mode 100644 index 00000000..323e2dae --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values-xlarge/integers.xml @@ -0,0 +1,7 @@ + + + 15 + 19 + 3 + + diff --git a/firetweet.component.nyan/src/main/res/values/colors.xml b/firetweet.component.nyan/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8011db6 --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #003366 + + diff --git a/firetweet.component.nyan/src/main/res/values/integers.xml b/firetweet.component.nyan/src/main/res/values/integers.xml new file mode 100644 index 00000000..52745dcd --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values/integers.xml @@ -0,0 +1,7 @@ + + + 8 + 11 + 1 + + diff --git a/firetweet.component.nyan/src/main/res/values/strings.xml b/firetweet.component.nyan/src/main/res/values/strings.xml new file mode 100644 index 00000000..2075de25 --- /dev/null +++ b/firetweet.component.nyan/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + Twidere Donate Live Wallpaper + Twidere Donate Wallpaper + Twidere Donate Daydream + + diff --git a/firetweet.component.querybuilder/.gitignore b/firetweet.component.querybuilder/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.component.querybuilder/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.component.querybuilder/build.gradle b/firetweet.component.querybuilder/build.gradle new file mode 100644 index 00000000..7ade2159 --- /dev/null +++ b/firetweet.component.querybuilder/build.gradle @@ -0,0 +1,40 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.component.querybuilder/proguard-rules.pro b/firetweet.component.querybuilder/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.component.querybuilder/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.component.querybuilder/src/androidTest/java/org/getlantern/twiderecomponentsqlquerybuilder/ApplicationTest.java b/firetweet.component.querybuilder/src/androidTest/java/org/getlantern/twiderecomponentsqlquerybuilder/ApplicationTest.java new file mode 100644 index 00000000..a0c7e64b --- /dev/null +++ b/firetweet.component.querybuilder/src/androidTest/java/org/getlantern/twiderecomponentsqlquerybuilder/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweetcomponentsqlquerybuilder; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.component.querybuilder/src/main/AndroidManifest.xml b/firetweet.component.querybuilder/src/main/AndroidManifest.xml new file mode 100644 index 00000000..56b347e4 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/AllColumns.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/AllColumns.java new file mode 100644 index 00000000..d615f327 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/AllColumns.java @@ -0,0 +1,47 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public class AllColumns implements Selectable { + + private final String table; + + public AllColumns() { + this(null); + } + + public AllColumns(final String table) { + this.table = table; + } + + @Override + public String getSQL() { + return table != null ? table + ".*" : "*"; + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Columns.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Columns.java new file mode 100644 index 00000000..8d4f9d7c --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Columns.java @@ -0,0 +1,109 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public class Columns implements Selectable { + + private final AbsColumn[] columns; + + public Columns(String... columns) { + this(Columns.fromStrings(columns)); + } + + public Columns(final AbsColumn... columns) { + this.columns = columns; + } + + private static Column[] fromStrings(String... columnsString) { + final Column[] columns = new Column[columnsString.length]; + for (int i = 0, j = columnsString.length; i < j; i++) { + columns[i] = new Column(columnsString[i]); + } + return columns; + } + + @Override + public String getSQL() { + return Utils.toString(columns, ',', true); + } + + public abstract static class AbsColumn implements Selectable { + + } + + public static class AllColumn extends AbsColumn { + + private final Table table; + + public AllColumn() { + this(null); + } + + public AllColumn(final Table table) { + this.table = table; + } + + @Override + public String getSQL() { + return table != null ? table.getSQL() + ".*" : "*"; + } + + } + + public static class Column extends AbsColumn { + + private final Table table; + private final String columnName, alias; + + public Column(final String columnName) { + this(null, columnName, null); + } + + public Column(final String columnName, final String alias) { + this(null, columnName, alias); + } + + public Column(final Table table, final String columnName) { + this(table, columnName, null); + } + + public Column(final Table table, final String columnName, final String alias) { + if (columnName == null) throw new IllegalArgumentException(""); + this.table = table; + this.columnName = columnName; + this.alias = alias; + } + + @Override + public String getSQL() { + final String col = table != null ? table.getSQL() + "." + columnName : columnName; + return alias != null ? col + " AS " + alias : col; + } + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Constraint.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Constraint.java new file mode 100644 index 00000000..f1992ffd --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Constraint.java @@ -0,0 +1,30 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.querybuilder; + +/** + * Created by mariotaku on 15/3/30. + */ +public class Constraint implements SQLLang { + @Override + public String getSQL() { + return null; + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Expression.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Expression.java new file mode 100644 index 00000000..353c762f --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Expression.java @@ -0,0 +1,147 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +import org.getlantern.querybuilder.Columns.Column; + +import java.util.Locale; + +public class Expression implements SQLLang { + private final String expr; + + public Expression(final String expr) { + this.expr = expr; + } + + public Expression(SQLLang lang) { + this(lang.getSQL()); + } + + public static Expression and(final Expression... expressions) { + return new Expression(toExpr(expressions, "AND")); + } + + public static Expression equals(final Column l, final Column r) { + return new Expression(String.format(Locale.ROOT, "%s = %s", l.getSQL(), r.getSQL())); + } + + public static Expression equals(final Column l, final Selectable r) { + return new Expression(String.format(Locale.ROOT, "%s = (%s)", l.getSQL(), r.getSQL())); + } + + public static Expression equals(final String l, final Selectable r) { + return new Expression(String.format(Locale.ROOT, "%s = (%s)", l, r.getSQL())); + } + + public static Expression equals(final Column l, final long r) { + return new Expression(String.format(Locale.ROOT, "%s = %d", l.getSQL(), r)); + } + + public static Expression equals(final Column l, final String r) { + return new Expression(String.format(Locale.ROOT, "%s = '%s'", l.getSQL(), r)); + } + + public static Expression equals(final String l, final long r) { + return new Expression(String.format(Locale.ROOT, "%s = %d", l, r)); + } + + public static Expression greaterThan(final String l, final long r) { + return new Expression(String.format(Locale.ROOT, "%s > %d", l, r)); + } + + public static Expression in(final Column column, final Selectable in) { + return new Expression(String.format("%s IN(%s)", column.getSQL(), in.getSQL())); + } + + public static Expression notEquals(final String l, final long r) { + return new Expression(String.format(Locale.ROOT, "%s != %d", l, r)); + } + + public static Expression notEquals(final String l, final String r) { + return new Expression(String.format("%s != %s", l, r)); + } + + public static Expression notIn(final Column column, final Selectable in) { + return new Expression(String.format("%s NOT IN(%s)", column.getSQL(), in.getSQL())); + } + + public static Expression notNull(final Column column) { + return new Expression(String.format("%s NOT NULL", column.getSQL())); + } + + public static Expression or(final Expression... expressions) { + return new Expression(toExpr(expressions, "OR")); + } + + private static String toExpr(final Expression[] array, final String token) { + final StringBuilder builder = new StringBuilder(); + builder.append('('); + final int length = array.length; + for (int i = 0; i < length; i++) { + if (i > 0) { + builder.append(String.format(" %s ", token)); + } + builder.append(array[i].getSQL()); + } + builder.append(')'); + return builder.toString(); + } + + public static Expression equalsArgs(String l) { + return new Expression(String.format(Locale.ROOT, "%s = ?", l)); + } + + public static Expression isNull(Column column) { + return new Expression(String.format(Locale.ROOT, "%s IS NULL", column.getSQL())); + } + + public static Expression greaterThan(Column column1, Column column2) { + return new Expression(String.format(Locale.ROOT, "%s > %s", column1.getSQL(), column2.getSQL())); + } + + public static Expression likeRaw(final Column column, final String pattern, final String escape) { + return new Expression(String.format(Locale.ROOT, "%s LIKE %s ESCAPE '%s'", column.getSQL(), pattern, escape)); + } + + + + public static Expression like(final Column column, final SQLLang expression) { + return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), expression.getSQL())); + } + + + public static Expression likeRaw(final Column column, final String pattern) { + return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), pattern)); + } + + + @Override + public String getSQL() { + return expr; + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Join.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Join.java new file mode 100644 index 00000000..63c42a76 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Join.java @@ -0,0 +1,71 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.querybuilder; + +/** + * Created by mariotaku on 15/1/12. + */ +public class Join implements SQLLang { + + private final boolean natural; + private final Operation operation; + private final Selectable source; + private final Expression on; + + public Join(boolean natural, Operation operation, Selectable source, Expression on) { + this.natural = natural; + this.operation = operation; + this.source = source; + this.on = on; + } + + @Override + public String getSQL() { + if (operation == null) throw new IllegalArgumentException("operation can't be null!"); + if (source == null) throw new IllegalArgumentException("source can't be null!"); + final StringBuilder builder = new StringBuilder(); + if (natural) { + builder.append("NATURAL "); + } + builder.append(operation.getSQL()); + builder.append(" JOIN "); + builder.append(source.getSQL()); + if (on != null) { + builder.append(" ON "); + builder.append(on.getSQL()); + } + return builder.toString(); + } + + public enum Operation implements SQLLang { + LEFT("LEFT"), LEFT_OUTER("LEFT OUTER"), INNER("INNER"), CROSS("CROSS"); + private final String op; + + Operation(String op) { + this.op = op; + } + + @Override + public String getSQL() { + return op; + } + + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/NewColumn.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/NewColumn.java new file mode 100644 index 00000000..e07b22c7 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/NewColumn.java @@ -0,0 +1,38 @@ +package org.getlantern.querybuilder; + +public class NewColumn implements SQLLang { + + private final String name; + private final String type; + + public NewColumn(final String name, final String type) { + this.name = name; + this.type = type; + } + + public static NewColumn[] createNewColumns(final String[] colNames, final String[] colTypes) { + if (colNames == null || colTypes == null || colNames.length != colTypes.length) + throw new IllegalArgumentException("length of columns and types not match."); + final NewColumn[] newColumns = new NewColumn[colNames.length]; + for (int i = 0, j = colNames.length; i < j; i++) { + newColumns[i] = new NewColumn(colNames[i], colTypes[i]); + } + return newColumns; + } + + public String getName() { + return name; + } + + @Override + public String getSQL() { + if (name == null || type == null) + throw new NullPointerException("name and type must not be null!"); + return String.format("%s %s", name, type); + } + + public String getType() { + return type; + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/OnConflict.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/OnConflict.java new file mode 100644 index 00000000..a53f7803 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/OnConflict.java @@ -0,0 +1,17 @@ +package org.getlantern.querybuilder; + +/** + * Created by mariotaku on 14-8-7. + */ +public enum OnConflict { + ROLLBACK("ROLLBACK"), ABORT("ABORT"), REPLACE("REPLACE"), FAIL("FAIL"), IGNORE("IGNORE"); + private final String action; + + OnConflict(final String action) { + this.action = action; + } + + public String getAction() { + return action; + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/OrderBy.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/OrderBy.java new file mode 100644 index 00000000..bd92a6e8 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/OrderBy.java @@ -0,0 +1,65 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + + +public class OrderBy implements SQLLang { + + private final String[] orderBy; + private final boolean[] ascending; + + public OrderBy(final String[] orderBy, final boolean[] ascending) { + this.orderBy = orderBy; + this.ascending = ascending; + } + + public OrderBy(final String... orderBy) { + this(orderBy, null); + } + + public OrderBy(final String orderBy, final boolean ascending) { + this.orderBy = new String[]{orderBy}; + this.ascending = new boolean[]{ascending}; + } + + @Override + public String getSQL() { + final StringBuilder sb = new StringBuilder(); + for (int i = 0, j = orderBy.length; i < j; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(orderBy[i]); + if (ascending != null) { + sb.append(ascending[i] ? " ASC" : " DESC"); + } + } + return sb.toString(); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/RawItemArray.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/RawItemArray.java new file mode 100644 index 00000000..f73953a0 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/RawItemArray.java @@ -0,0 +1,24 @@ +package org.getlantern.querybuilder; + +public class RawItemArray implements Selectable { + + private final Object[] array; + + public RawItemArray(final long[] array) { + final Long[] converted = new Long[array.length]; + for (int i = 0, j = array.length; i < j; i++) { + converted[i] = array[i]; + } + this.array = converted; + } + + public RawItemArray(final Object[] array) { + this.array = array; + } + + @Override + public String getSQL() { + return Utils.toString(array, ',', false); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLFunctions.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLFunctions.java new file mode 100644 index 00000000..4e255161 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLFunctions.java @@ -0,0 +1,17 @@ +package org.getlantern.querybuilder; + +public class SQLFunctions { + + public static String SUM(final String val) { + return String.format("SUM (%s)", val); + } + + public static String COUNT() { + return COUNT("*"); + } + + public static String COUNT(final String val) { + return String.format("COUNT (%s)", val); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLLang.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLLang.java new file mode 100644 index 00000000..146c3363 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLLang.java @@ -0,0 +1,38 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public interface SQLLang extends Cloneable { + + /** + * Build SQL query string + * + * @return SQL query + */ + public String getSQL(); +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQuery.java new file mode 100644 index 00000000..ceab100c --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQuery.java @@ -0,0 +1,7 @@ +package org.getlantern.querybuilder; + +/** + * Created by mariotaku on 14-8-6. + */ +public interface SQLQuery extends SQLLang { +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQueryBuilder.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQueryBuilder.java new file mode 100644 index 00000000..7fc24b73 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQueryBuilder.java @@ -0,0 +1,124 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +import org.getlantern.querybuilder.query.SQLAlterTableQuery; +import org.getlantern.querybuilder.query.SQLCreateIndexQuery; +import org.getlantern.querybuilder.query.SQLCreateTableQuery; +import org.getlantern.querybuilder.query.SQLCreateTriggerQuery; +import org.getlantern.querybuilder.query.SQLCreateViewQuery; +import org.getlantern.querybuilder.query.SQLDeleteQuery; +import org.getlantern.querybuilder.query.SQLDropTableQuery; +import org.getlantern.querybuilder.query.SQLDropTriggerQuery; +import org.getlantern.querybuilder.query.SQLDropViewQuery; +import org.getlantern.querybuilder.query.SQLInsertQuery; +import org.getlantern.querybuilder.query.SQLSelectQuery; +import org.getlantern.querybuilder.query.SQLUpdateQuery; + +public class SQLQueryBuilder { + + private SQLQueryBuilder() { + throw new AssertionError("You can't create instance for this class"); + } + + public static SQLAlterTableQuery.Builder alterTable(final String table) { + return new SQLAlterTableQuery.Builder().alterTable(table); + } + + public static SQLCreateTableQuery.Builder createTable(final boolean temporary, final boolean createIfNotExists, + final String name) { + return new SQLCreateTableQuery.Builder().createTable(temporary, createIfNotExists, name); + } + + public static SQLCreateTableQuery.Builder createTable(final boolean createIfNotExists, final String name) { + return createTable(false, createIfNotExists, name); + } + + public static SQLCreateTableQuery.Builder createTable(final String name) { + return createTable(false, false, name); + } + + public static SQLCreateViewQuery.Builder createView(final boolean temporary, final boolean createIfNotExists, + final String name) { + return new SQLCreateViewQuery.Builder().createView(temporary, createIfNotExists, name); + } + + public static SQLCreateIndexQuery.Builder createIndex(final boolean unique, final boolean createIfNotExists) { + return new SQLCreateIndexQuery.Builder().createIndex(unique, createIfNotExists); + } + + + public static SQLCreateTriggerQuery.Builder createTrigger(final boolean temporary, final boolean createIfNotExists, + final String name) { + return new SQLCreateTriggerQuery.Builder().createTrigger(temporary, createIfNotExists, name); + } + + public static SQLCreateViewQuery.Builder createView(final boolean createIfNotExists, final String name) { + return createView(false, createIfNotExists, name); + } + + public static SQLCreateViewQuery.Builder createView(final String name) { + return createView(false, false, name); + } + + public static SQLDeleteQuery.Builder deleteFrom(Table table) { + return new SQLDeleteQuery.Builder().from(table); + } + + public static SQLDropTableQuery dropTable(final boolean dropIfExists, final String table) { + return new SQLDropTableQuery(dropIfExists, table); + } + + public static SQLDropViewQuery dropView(final boolean dropIfExists, final String table) { + return new SQLDropViewQuery(dropIfExists, table); + } + + public static SQLDropTriggerQuery dropTrigger(final boolean dropIfExists, final String table) { + return new SQLDropTriggerQuery(dropIfExists, table); + } + + public static SQLInsertQuery.Builder insertInto(final OnConflict onConflict, final String table) { + return new SQLInsertQuery.Builder().insertInto(onConflict, table); + } + + public static SQLUpdateQuery.Builder update(final OnConflict onConflict, final Table table) { + return new SQLUpdateQuery.Builder().update(onConflict, table); + } + + public static SQLInsertQuery.Builder insertInto(final String table) { + return insertInto(null, table); + } + + public static SQLSelectQuery.Builder select(final boolean distinct, final Selectable select) { + return new SQLSelectQuery.Builder().select(distinct, select); + } + + public static SQLSelectQuery.Builder select(final Selectable select) { + return select(false, select); + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQueryException.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQueryException.java new file mode 100644 index 00000000..bcf18f18 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SQLQueryException.java @@ -0,0 +1,49 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public class SQLQueryException extends RuntimeException { + + private static final long serialVersionUID = 910158450604676104L; + + public SQLQueryException() { + } + + public SQLQueryException(final String detailMessage) { + super(detailMessage); + } + + public SQLQueryException(final String detailMessage, final Throwable throwable) { + super(detailMessage, throwable); + } + + public SQLQueryException(final Throwable throwable) { + super(throwable); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Selectable.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Selectable.java new file mode 100644 index 00000000..f2ea59ac --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Selectable.java @@ -0,0 +1,32 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public interface Selectable extends SQLLang { + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SetValue.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SetValue.java new file mode 100644 index 00000000..2ffd5445 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/SetValue.java @@ -0,0 +1,23 @@ +package org.getlantern.querybuilder; + +import java.util.Locale; + +/** + * Created by mariotaku on 14-8-7. + */ +public class SetValue implements SQLLang { + + private final Columns.Column column; + private final SQLLang expression; + + public SetValue(Columns.Column column, SQLLang expression) { + this.column = column; + this.expression = expression; + } + + + @Override + public String getSQL() { + return String.format(Locale.ROOT, "%s = %s", column.getSQL(), expression.getSQL()); + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Table.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Table.java new file mode 100644 index 00000000..4c35a61b --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Table.java @@ -0,0 +1,45 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public class Table implements Selectable { + + public static final Table NEW = new Table("NEW"); + + private final String table; + + public Table(final String table) { + this.table = table; + } + + @Override + public String getSQL() { + return table; + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Tables.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Tables.java new file mode 100644 index 00000000..91e30f53 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Tables.java @@ -0,0 +1,44 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public class Tables extends Table { + + private final String[] tables; + + public Tables(final String... tables) { + super(null); + this.tables = tables; + } + + @Override + public String getSQL() { + return Utils.toString(tables, ',', false); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Utils.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Utils.java new file mode 100644 index 00000000..42eff86b --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/Utils.java @@ -0,0 +1,53 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder; + +public class Utils { + + public static String toString(final Object[] array, final char token, final boolean includeSpace) { + final StringBuilder builder = new StringBuilder(); + final int length = array.length; + for (int i = 0; i < length; i++) { + final String string = objectToString(array[i]); + if (string != null) { + if (i > 0) { + builder.append(includeSpace ? token + " " : token); + } + builder.append(string); + } + } + return builder.toString(); + } + + private static String objectToString(Object o) { + if (o instanceof SQLLang) + return ((SQLLang) o).getSQL(); + return o != null ? o.toString() : null; + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/IBuilder.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/IBuilder.java new file mode 100644 index 00000000..1f68670c --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/IBuilder.java @@ -0,0 +1,16 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.SQLLang; + +public interface IBuilder { + + public T build(); + + /** + * Equivalent to {@link #build()}.{@link SQLLang#getSQL()} + * + * @return + */ + public String buildSQL(); + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLAlterTableQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLAlterTableQuery.java new file mode 100644 index 00000000..d5f1f946 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLAlterTableQuery.java @@ -0,0 +1,70 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.NewColumn; +import org.getlantern.querybuilder.SQLQuery; + +public class SQLAlterTableQuery implements SQLQuery { + + private String table; + private String renameTo; + private NewColumn addColumn; + + @Override + public String getSQL() { + if (table == null) throw new NullPointerException("table must not be null!"); + if (renameTo == null && addColumn == null) throw new NullPointerException(); + if (renameTo != null) return String.format("ALTER TABLE %s RENAME TO %s", table, renameTo); + return String.format("ALTER TABLE %s ADD COLUMN %s", table, addColumn.getSQL()); + } + + void setAddColumn(final NewColumn addColumn) { + this.addColumn = addColumn; + } + + void setRenameTo(final String renameTo) { + this.renameTo = renameTo; + } + + void setTable(final String table) { + this.table = table; + } + + public static final class Builder implements IBuilder { + + private final SQLAlterTableQuery query = new SQLAlterTableQuery(); + private boolean buildCalled; + + public Builder addColumn(final NewColumn addColumn) { + checkNotBuilt(); + query.setAddColumn(addColumn); + return this; + } + + public Builder alterTable(final String table) { + checkNotBuilt(); + query.setTable(table); + return this; + } + + @Override + public SQLAlterTableQuery build() { + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder renameTo(final String renameTo) { + checkNotBuilt(); + query.setRenameTo(renameTo); + return this; + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateIndexQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateIndexQuery.java new file mode 100644 index 00000000..2a3f953e --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateIndexQuery.java @@ -0,0 +1,135 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.Columns; +import org.getlantern.querybuilder.Expression; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.Table; + +public class SQLCreateIndexQuery implements SQLQuery { + + private boolean unique; + private boolean createIfNotExists; + private Table table; + private String indexName; + private Columns indexedColumns; + private Expression where; + + SQLCreateIndexQuery() { + + } + + @Override + public String getSQL() { + if (table == null) throw new NullPointerException("Table must not be null!"); + if (indexName == null) + throw new NullPointerException("SELECT statement must not be null!"); + final StringBuilder sb = new StringBuilder("CREATE"); + if (unique) { + sb.append(" UNIQUE"); + } + sb.append(" INDEX"); + if (createIfNotExists) { + sb.append(" IF NOT EXISTS"); + } + if (indexedColumns == null) + throw new NullPointerException("Indexed columns must not be null !"); + sb.append(String.format(" %s ON %s (%s)", indexName, table.getSQL(), indexedColumns.getSQL())); + if (where != null) { + sb.append(" WHERE"); + sb.append(where.getSQL()); + } + return sb.toString(); + } + + public void setIndexedColumns(Columns indexedColumns) { + this.indexedColumns = indexedColumns; + } + + public void setWhere(Expression where) { + this.where = where; + } + + void setIndexName(final String indexName) { + this.indexName = indexName; + } + + void setCreateIfNotExists(final boolean createIfNotExists) { + this.createIfNotExists = createIfNotExists; + } + + void setTable(final Table table) { + this.table = table; + } + + void setUnique(final boolean unique) { + this.unique = unique; + } + + public static final class Builder implements IBuilder { + + private final SQLCreateIndexQuery query = new SQLCreateIndexQuery(); + private boolean buildCalled; + + public Builder on(final Table table, Columns indexedColumns) { + checkNotBuilt(); + query.setTable(table); + query.setIndexedColumns(indexedColumns); + return this; + } + + public Builder name(final String name) { + checkNotBuilt(); + query.setIndexName(name); + return this; + } + + public Builder where(final Expression expression) { + checkNotBuilt(); + query.setWhere(expression); + return this; + } + + + @Override + public SQLCreateIndexQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + + public Builder createIndex(final boolean unique, final boolean createIfNotExists) { + checkNotBuilt(); + query.setUnique(unique); + query.setCreateIfNotExists(createIfNotExists); + return this; + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateTableQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateTableQuery.java new file mode 100644 index 00000000..2d9fa67b --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateTableQuery.java @@ -0,0 +1,132 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.Constraint; +import org.getlantern.querybuilder.NewColumn; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.Utils; + +public class SQLCreateTableQuery implements SQLQuery { + + private boolean temporary; + private boolean createIfNotExists; + private String table; + private NewColumn[] newColumns; + private SQLSelectQuery selectStmt; + private Constraint[] constraints; + + SQLCreateTableQuery() { + } + + @Override + public String getSQL() { + if (table == null) throw new NullPointerException("NAME must not be null!"); + if ((newColumns == null || newColumns.length == 0) && selectStmt == null) + throw new NullPointerException("Columns or AS must not be null!"); + final StringBuilder sb = new StringBuilder("CREATE "); + if (temporary) { + sb.append("TEMPORARY "); + } + sb.append("TABLE "); + if (createIfNotExists) { + sb.append("IF NOT EXISTS "); + } + sb.append(table); + sb.append(' '); + if (newColumns != null && newColumns.length > 0) { + sb.append('('); + sb.append(Utils.toString(newColumns, ',', true)); + if (constraints != null) { + sb.append(' '); + sb.append(Utils.toString(constraints, ',', true)); + sb.append(' '); + } + sb.append(')'); + } else { + sb.append("AS "); + sb.append(selectStmt.getSQL()); + } + return sb.toString(); + } + + void setAs(final SQLSelectQuery selectStmt) { + this.selectStmt = selectStmt; + } + + void setCreateIfNotExists(final boolean createIfNotExists) { + this.createIfNotExists = createIfNotExists; + } + + void setNewColumns(final NewColumn[] newColumns) { + this.newColumns = newColumns; + } + + void setTable(final String table) { + this.table = table; + } + + void setTemporary(final boolean temporary) { + this.temporary = temporary; + } + + public static final class Builder implements IBuilder { + + private final SQLCreateTableQuery query = new SQLCreateTableQuery(); + + private boolean buildCalled; + + public Builder as(final SQLSelectQuery selectStmt) { + checkNotBuilt(); + query.setAs(selectStmt); + return this; + } + + @Override + public SQLCreateTableQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder columns(final NewColumn... newColumns) { + checkNotBuilt(); + query.setNewColumns(newColumns); + return this; + } + + public Builder constraint(final Constraint... constraints) { + checkNotBuilt(); + query.setConstraints(constraints); + return this; + } + + public Builder createTable(final boolean temporary, final boolean createIfNotExists, final String table) { + checkNotBuilt(); + query.setTemporary(temporary); + query.setCreateIfNotExists(createIfNotExists); + query.setTable(table); + return this; + } + + public Builder createTable(final boolean createIfNotExists, final String table) { + return createTable(false, createIfNotExists, table); + } + + public Builder createTemporaryTable(final boolean createIfNotExists, final String table) { + return createTable(true, createIfNotExists, table); + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + + } + + private void setConstraints(Constraint[] constraints) { + this.constraints = constraints; + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateTriggerQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateTriggerQuery.java new file mode 100644 index 00000000..476daf34 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateTriggerQuery.java @@ -0,0 +1,202 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.Columns; +import org.getlantern.querybuilder.Expression; +import org.getlantern.querybuilder.SQLLang; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.Table; +import org.getlantern.querybuilder.Utils; + +import java.util.Locale; + +/** + * Created by mariotaku on 14-8-6. + */ +public class SQLCreateTriggerQuery implements SQLQuery { + + private boolean temporary; + private boolean createIfNotExists; + private boolean forEachRow; + private String name; + private Table on; + private Type type; + private Event event; + private Columns updateOf; + private SQLQuery[] actions; + private Expression when; + + void setActions(SQLQuery[] actions) { + this.actions = actions; + } + + void setForEachRow(boolean forEachRow) { + this.forEachRow = forEachRow; + } + + void setOn(Table on) { + this.on = on; + } + + void setUpdateOf(Columns updateOf) { + this.updateOf = updateOf; + } + + void setType(Type type) { + this.type = type; + } + + void setEvent(Event event) { + this.event = event; + } + + void setWhen(Expression when) { + this.when = when; + } + + @Override + public String getSQL() { + if (name == null) throw new NullPointerException("NAME must not be null!"); + if (event == null) throw new NullPointerException("EVENT must not be null!"); + if (on == null) throw new NullPointerException("ON must not be null!"); + if (actions == null) throw new NullPointerException("ACTIONS must not be null!"); + final StringBuilder sb = new StringBuilder("CREATE "); + if (temporary) { + sb.append("TEMPORARY "); + } + sb.append("TRIGGER "); + if (createIfNotExists) { + sb.append("IF NOT EXISTS "); + } + sb.append(name); + sb.append(' '); + if (type != null) { + sb.append(type.getSQL()); + sb.append(' '); + } + sb.append(event.getSQL()); + sb.append(' '); + if (event == Event.UPDATE) { + sb.append(String.format(Locale.ROOT, "%s ", updateOf.getSQL())); + } + sb.append(String.format(Locale.ROOT, "ON %s ", on.getSQL())); + if (forEachRow) { + sb.append("FOR EACH ROW "); + } + if (when != null) { + sb.append(String.format(Locale.ROOT, "WHEN %s ", when.getSQL())); + } + sb.append(String.format(Locale.ROOT, "BEGIN %s; END", Utils.toString(actions, ';', true))); + return sb.toString(); + } + + void setCreateIfNotExists(final boolean createIfNotExists) { + this.createIfNotExists = createIfNotExists; + } + + void setName(final String name) { + this.name = name; + } + + void setTemporary(final boolean temporary) { + this.temporary = temporary; + } + + public static enum Type implements SQLLang { + BEFORE("BEFORE"), AFTER("AFTER"), INSTEAD_OF("INSTEAD OF"); + private final String lang; + + Type(String lang) { + this.lang = lang; + } + + @Override + public String getSQL() { + return lang; + } + } + + public static enum Event implements SQLLang { + INSERT("INSERT"), DELETE("DELETE"), UPDATE("UPDATE"); + private final String lang; + + Event(String lang) { + this.lang = lang; + } + + @Override + public String getSQL() { + return lang; + } + } + + public static class Builder implements IBuilder { + + private final SQLCreateTriggerQuery query = new SQLCreateTriggerQuery(); + private boolean buildCalled; + + public Builder forEachRow(final boolean forEachRow) { + checkNotBuilt(); + query.setForEachRow(forEachRow); + return this; + } + + public Builder on(final Table on) { + checkNotBuilt(); + query.setOn(on); + return this; + } + + public Builder event(Event event) { + checkNotBuilt(); + query.setEvent(event); + return this; + } + + public Builder type(Type type) { + checkNotBuilt(); + query.setType(type); + return this; + } + + public Builder updateOf(Columns updateOf) { + checkNotBuilt(); + query.setUpdateOf(updateOf); + return this; + } + + public Builder actions(SQLQuery... actions) { + checkNotBuilt(); + query.setActions(actions); + return this; + } + + public Builder when(Expression when) { + checkNotBuilt(); + query.setWhen(when); + return this; + } + + @Override + public SQLCreateTriggerQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + + public Builder createTrigger(boolean temporary, boolean createIfNotExists, String name) { + checkNotBuilt(); + query.setTemporary(temporary); + query.setCreateIfNotExists(createIfNotExists); + query.setName(name); + return this; + } + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateViewQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateViewQuery.java new file mode 100644 index 00000000..f88208ee --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLCreateViewQuery.java @@ -0,0 +1,91 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.SQLQuery; + +public class SQLCreateViewQuery implements SQLQuery { + + private boolean temporary; + private boolean createIfNotExists; + private String name; + private SQLSelectQuery selectStmt; + + SQLCreateViewQuery() { + + } + + @Override + public String getSQL() { + if (name == null) throw new NullPointerException("NAME must not be null!"); + if (selectStmt == null) + throw new NullPointerException("SELECT statement must not be null!"); + final StringBuilder sb = new StringBuilder("CREATE "); + if (temporary) { + sb.append("TEMPORARY "); + } + sb.append("VIEW "); + if (createIfNotExists) { + sb.append("IF NOT EXISTS "); + } + sb.append(String.format("%s AS %s", name, selectStmt.getSQL())); + return sb.toString(); + } + + void setAs(final SQLSelectQuery selectStmt) { + this.selectStmt = selectStmt; + } + + void setCreateIfNotExists(final boolean createIfNotExists) { + this.createIfNotExists = createIfNotExists; + } + + void setName(final String name) { + this.name = name; + } + + void setTemporary(final boolean temporary) { + this.temporary = temporary; + } + + public static final class Builder implements IBuilder { + + private final SQLCreateViewQuery query = new SQLCreateViewQuery(); + private boolean buildCalled; + + public Builder as(final SQLSelectQuery selectStmt) { + checkNotBuilt(); + query.setAs(selectStmt); + return this; + } + + @Override + public SQLCreateViewQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder createTemporaryView(final boolean createIfNotExists, final String name) { + return createView(true, createIfNotExists, name); + } + + public Builder createView(final boolean temporary, final boolean createIfNotExists, final String name) { + checkNotBuilt(); + query.setTemporary(temporary); + query.setCreateIfNotExists(createIfNotExists); + query.setName(name); + return this; + } + + public Builder createView(final boolean createIfNotExists, final String name) { + return createView(false, createIfNotExists, name); + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDeleteQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDeleteQuery.java new file mode 100644 index 00000000..486275aa --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDeleteQuery.java @@ -0,0 +1,58 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.Expression; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.Table; + +public class SQLDeleteQuery implements SQLQuery { + + private Table table; + private Expression where; + + @Override + public String getSQL() { + if (where == null) return String.format("DELETE FROM %s", table.getSQL()); + return String.format("DELETE FROM %S WHERE %s", table.getSQL(), where.getSQL()); + } + + void setFrom(final Table table) { + this.table = table; + } + + void setWhere(final Expression where) { + this.where = where; + } + + public static final class Builder implements IBuilder { + private final SQLDeleteQuery query = new SQLDeleteQuery(); + private boolean buildCalled; + + @Override + public SQLDeleteQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder from(final Table table) { + checkNotBuilt(); + query.setFrom(table); + return this; + } + + public Builder where(final Expression where) { + checkNotBuilt(); + query.setWhere(where); + return this; + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropQuery.java new file mode 100644 index 00000000..bfa15a66 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropQuery.java @@ -0,0 +1,24 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.SQLQuery; + +public class SQLDropQuery implements SQLQuery { + + private final boolean dropIfExists; + private final String type; + private final String target; + + public SQLDropQuery(final boolean dropIfExists, final String type, final String target) { + if (target == null) throw new NullPointerException(); + this.dropIfExists = dropIfExists; + this.type = type; + this.target = target; + } + + @Override + public final String getSQL() { + if (dropIfExists) return String.format("DROP %s IF EXISTS %s", type, target); + return String.format("DROP %s %s", type, target); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropTableQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropTableQuery.java new file mode 100644 index 00000000..d3ae4669 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropTableQuery.java @@ -0,0 +1,9 @@ +package org.getlantern.querybuilder.query; + +public class SQLDropTableQuery extends SQLDropQuery { + + public SQLDropTableQuery(final boolean dropIfExists, final String table) { + super(dropIfExists, "TABLE", table); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropTriggerQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropTriggerQuery.java new file mode 100644 index 00000000..9aaa61f9 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropTriggerQuery.java @@ -0,0 +1,9 @@ +package org.getlantern.querybuilder.query; + +public class SQLDropTriggerQuery extends SQLDropQuery { + + public SQLDropTriggerQuery(final boolean dropIfExists, final String table) { + super(dropIfExists, "TRIGGER", table); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropViewQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropViewQuery.java new file mode 100644 index 00000000..f812d738 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLDropViewQuery.java @@ -0,0 +1,9 @@ +package org.getlantern.querybuilder.query; + +public class SQLDropViewQuery extends SQLDropQuery { + + public SQLDropViewQuery(final boolean dropIfExists, final String table) { + super(dropIfExists, "VIEW", table); + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLInsertQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLInsertQuery.java new file mode 100644 index 00000000..2d2245fb --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLInsertQuery.java @@ -0,0 +1,94 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.OnConflict; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.Utils; + +public class SQLInsertQuery implements SQLQuery { + + private OnConflict onConflict; + private String table; + private String[] columns; + private SQLSelectQuery select; + + SQLInsertQuery() { + + } + + @Override + public String getSQL() { + if (table == null) throw new NullPointerException("table must not be null!"); + final StringBuilder sb = new StringBuilder(); + sb.append("INSERT "); + if (onConflict != null) { + sb.append(String.format("OR %s ", onConflict.getAction())); + } + sb.append(String.format("INTO %s ", table)); + sb.append(String.format("(%s) ", Utils.toString(columns, ',', false))); + sb.append(String.format("%s ", select.getSQL())); + return sb.toString(); + } + + void setColumns(final String[] columns) { + this.columns = columns; + } + + void setOnConflict(final OnConflict onConflict) { + this.onConflict = onConflict; + } + + void setSelect(final SQLSelectQuery select) { + this.select = select; + } + + void setTable(final String table) { + this.table = table; + } + + public static final class Builder implements IBuilder { + + private final SQLInsertQuery query = new SQLInsertQuery(); + + private boolean buildCalled; + + @Override + public SQLInsertQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder columns(final String[] columns) { + checkNotBuilt(); + query.setColumns(columns); + return this; + } + + public Builder insertInto(final OnConflict onConflict, final String table) { + checkNotBuilt(); + query.setOnConflict(onConflict); + query.setTable(table); + return this; + } + + public Builder insertInto(final String table) { + return insertInto(null, table); + } + + public Builder select(final SQLSelectQuery select) { + checkNotBuilt(); + query.setSelect(select); + return this; + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + + } + +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLSelectQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLSelectQuery.java new file mode 100644 index 00000000..5b988063 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLSelectQuery.java @@ -0,0 +1,280 @@ +/** + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + */ + +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.Expression; +import org.getlantern.querybuilder.Join; +import org.getlantern.querybuilder.OrderBy; +import org.getlantern.querybuilder.SQLLang; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.SQLQueryException; +import org.getlantern.querybuilder.Selectable; + +import java.util.ArrayList; +import java.util.List; + +public class SQLSelectQuery implements SQLQuery, Selectable { + + private final List internalQueries = new ArrayList<>(); + + private InternalQuery currentInternalQuery; + private OrderBy orderBy; + private Integer limit = null, offset = null; + + SQLSelectQuery() { + initCurrentQuery(); + } + + @Override + public String getSQL() { + final StringBuilder sb = new StringBuilder(); + final int size = internalQueries.size(); + for (int i = 0; i < size; i++) { + if (i != 0) { + sb.append("UNION "); + } + final InternalQuery query = internalQueries.get(i); + sb.append(query.getSQL()); + } + if (orderBy != null) { + sb.append(String.format("ORDER BY %s ", orderBy.getSQL())); + } + if (limit != null) { + sb.append(String.format("LIMIT %s ", limit)); + if (offset != null) { + sb.append(String.format("OFFSET %s ", offset)); + } + } + return sb.toString(); + } + + private void initCurrentQuery() { + currentInternalQuery = new InternalQuery(); + internalQueries.add(currentInternalQuery); + } + + void setDistinct(final boolean distinct) { + currentInternalQuery.setDistinct(distinct); + } + + void setFrom(final Selectable from) { + currentInternalQuery.setFrom(from); + } + + void setGroupBy(final Selectable groupBy) { + currentInternalQuery.setGroupBy(groupBy); + } + + void setHaving(final Expression having) { + currentInternalQuery.setHaving(having); + } + + void setJoin(final Join join) { + currentInternalQuery.setJoin(join); + } + + void setLimit(final int limit) { + this.limit = limit; + } + + void setOffset(final int offset) { + this.offset = offset; + } + + void setOrderBy(final OrderBy orderBy) { + this.orderBy = orderBy; + } + + void setSelect(final Selectable select) { + currentInternalQuery.setSelect(select); + } + + void setWhere(final Expression where) { + currentInternalQuery.setWhere(where); + } + + void union() { + initCurrentQuery(); + } + + public static final class Builder implements IBuilder { + private final SQLSelectQuery query = new SQLSelectQuery(); + private boolean buildCalled; + + @Override + public SQLSelectQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder from(final Selectable from) { + checkNotBuilt(); + query.setFrom(from); + return this; + } + + public Builder groupBy(final Selectable groupBy) { + checkNotBuilt(); + query.setGroupBy(groupBy); + return this; + } + + public Builder having(final Expression having) { + checkNotBuilt(); + query.setHaving(having); + return this; + } + + + public Builder limit(final int limit) { + checkNotBuilt(); + query.setLimit(limit); + return this; + } + + public Builder join(final Join join) { + checkNotBuilt(); + query.setJoin(join); + return this; + } + + public Builder offset(final int offset) { + query.setOffset(offset); + return this; + } + + public Builder orderBy(final OrderBy orderBy) { + checkNotBuilt(); + query.setOrderBy(orderBy); + return this; + } + + public Builder select(final boolean distinct, final Selectable select) { + checkNotBuilt(); + query.setSelect(select); + query.setDistinct(distinct); + return this; + } + + public Builder select(final Selectable select) { + checkNotBuilt(); + select(false, select); + return this; + } + + public Builder union() { + checkNotBuilt(); + query.union(); + return this; + } + + public Builder where(final Expression where) { + checkNotBuilt(); + query.setWhere(where); + return this; + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + + } + + private static class InternalQuery implements SQLLang { + + private boolean distinct; + private Selectable select, from, groupBy; + private Expression where, having; + private Join join; + + @Override + public String getSQL() { + if (select == null) throw new SQLQueryException("selectable is null"); + final StringBuilder sb = new StringBuilder("SELECT "); + if (distinct) { + sb.append("DISTINCT "); + } + sb.append(String.format("%s ", select.getSQL())); + if (!(select instanceof SQLSelectQuery) && from == null) + throw new SQLQueryException("FROM not specified"); + else if (from != null) { + if (from instanceof SQLSelectQuery) { + sb.append(String.format("FROM (%s) ", from.getSQL())); + } else { + sb.append(String.format("FROM %s ", from.getSQL())); + } + } + if (join != null) { + sb.append(String.format("%s ", join.getSQL())); + } + if (where != null) { + sb.append(String.format("WHERE %s ", where.getSQL())); + } + if (groupBy != null) { + sb.append(String.format("GROUP BY %s ", groupBy.getSQL())); + if (having != null) { + sb.append(String.format("HAVING %s ", having.getSQL())); + } + } + return sb.toString(); + } + + void setJoin(final Join join) { + this.join = join; + } + + void setDistinct(final boolean distinct) { + this.distinct = distinct; + } + + void setFrom(final Selectable from) { + this.from = from; + } + + void setGroupBy(final Selectable groupBy) { + this.groupBy = groupBy; + } + + void setHaving(final Expression having) { + this.having = having; + } + + void setSelect(final Selectable select) { + this.select = select; + } + + void setWhere(final Expression where) { + this.where = where; + } + } +} diff --git a/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLUpdateQuery.java b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLUpdateQuery.java new file mode 100644 index 00000000..df690ab9 --- /dev/null +++ b/firetweet.component.querybuilder/src/main/java/org/getlantern/querybuilder/query/SQLUpdateQuery.java @@ -0,0 +1,101 @@ +package org.getlantern.querybuilder.query; + +import org.getlantern.querybuilder.Expression; +import org.getlantern.querybuilder.OnConflict; +import org.getlantern.querybuilder.SQLQuery; +import org.getlantern.querybuilder.SetValue; +import org.getlantern.querybuilder.Table; +import org.getlantern.querybuilder.Utils; + +import java.util.Locale; + +public class SQLUpdateQuery implements SQLQuery { + + private OnConflict onConflict; + private Table table; + private SetValue[] values; + private Expression where; + + SQLUpdateQuery() { + + } + + @Override + public String getSQL() { + if (table == null) throw new NullPointerException("table must not be null!"); + final StringBuilder sb = new StringBuilder(); + sb.append("UPDATE "); + if (onConflict != null) { + sb.append(String.format(Locale.ROOT, "OR %s ", onConflict.getAction())); + } + sb.append(String.format(Locale.ROOT, "%s ", table.getSQL())); + sb.append(String.format(Locale.ROOT, "SET %s ", Utils.toString(values, ',', false))); + if (where != null) { + sb.append(String.format(Locale.ROOT, "WHERE %s ", where.getSQL())); + } + return sb.toString(); + } + + void setWhere(final Expression where) { + this.where = where; + } + + void setValues(final SetValue[] columns) { + this.values = columns; + } + + void setOnConflict(final OnConflict onConflict) { + this.onConflict = onConflict; + } + + void setTable(final Table table) { + this.table = table; + } + + public static final class Builder implements IBuilder { + + private final SQLUpdateQuery query = new SQLUpdateQuery(); + + private boolean buildCalled; + + @Override + public SQLUpdateQuery build() { + buildCalled = true; + return query; + } + + @Override + public String buildSQL() { + return build().getSQL(); + } + + public Builder set(final SetValue... values) { + checkNotBuilt(); + query.setValues(values); + return this; + } + + public Builder where(final Expression where) { + checkNotBuilt(); + query.setWhere(where); + return this; + } + + public Builder update(final OnConflict onConflict, final Table table) { + checkNotBuilt(); + query.setOnConflict(onConflict); + query.setTable(table); + return this; + } + + public Builder update(final Table table) { + return update(null, table); + } + + private void checkNotBuilt() { + if (buildCalled) throw new IllegalStateException(); + } + + } + +} diff --git a/firetweet.component.twitter4j.streaming/.gitignore b/firetweet.component.twitter4j.streaming/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.component.twitter4j.streaming/build.gradle b/firetweet.component.twitter4j.streaming/build.gradle new file mode 100644 index 00000000..d36674ec --- /dev/null +++ b/firetweet.component.twitter4j.streaming/build.gradle @@ -0,0 +1,41 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile project(':firetweet.component.twitter4j') + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.component.twitter4j.streaming/proguard-rules.pro b/firetweet.component.twitter4j.streaming/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.component.twitter4j.streaming/src/androidTest/java/org/getlantern/firetweet/library/twitter4j/streaming/ApplicationTest.java b/firetweet.component.twitter4j.streaming/src/androidTest/java/org/getlantern/firetweet/library/twitter4j/streaming/ApplicationTest.java new file mode 100644 index 00000000..74e85a82 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/androidTest/java/org/getlantern/firetweet/library/twitter4j/streaming/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.library.twitter4j.streaming; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/AndroidManifest.xml b/firetweet.component.twitter4j.streaming/src/main/AndroidManifest.xml new file mode 100644 index 00000000..83e7618b --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/ConnectionLifeCycleListener.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/ConnectionLifeCycleListener.java new file mode 100644 index 00000000..e29ee966 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/ConnectionLifeCycleListener.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.7 + */ +public interface ConnectionLifeCycleListener { + /** + * called before thread gets cleaned up + */ + void onCleanUp(); + + /** + * called after connection was established + */ + void onConnect(); + + /** + * called after connection was disconnected + */ + void onDisconnect(); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/ControlStreamInfo.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/ControlStreamInfo.java new file mode 100644 index 00000000..be96b3a2 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/ControlStreamInfo.java @@ -0,0 +1,115 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * Copyright (C) 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +import java.io.Serializable; +import java.util.Arrays; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * @author Yusuke Yamamoto - yusuke at twitter.com + * @since Twitter4J 2.2.6 + */ +public final class ControlStreamInfo implements Serializable { + private static final long serialVersionUID = -6761659771734942177L; + private final StreamController.User[] users; + private final boolean includeFollowingsActivity; + private final boolean includeUserChanges; + private final String replies; + private final String with; + private transient final StreamController controller; + + /* package */ControlStreamInfo(final StreamController controller, final JSONObject json) throws TwitterException { + this.controller = controller; + try { + final JSONObject info = json.getJSONObject("info"); + includeFollowingsActivity = getBoolean("include_followings_activity", info); + includeUserChanges = getBoolean("include_user_changes", info); + replies = getRawString("replies", info); + with = getRawString("with", info); + final JSONArray usersJSON = info.getJSONArray("users"); + users = new StreamController.User[usersJSON.length()]; + for (int i = 0; i < usersJSON.length(); i++) { + users[i] = this.controller.createUser(usersJSON.getJSONObject(i)); + } + + } catch (final JSONException e) { + throw new TwitterException(e); + } + + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ControlStreamInfo that = (ControlStreamInfo) o; + + if (includeFollowingsActivity != that.includeFollowingsActivity) return false; + if (includeUserChanges != that.includeUserChanges) return false; + if (replies != null ? !replies.equals(that.replies) : that.replies != null) return false; + if (!Arrays.equals(users, that.users)) return false; + if (with != null ? !with.equals(that.with) : that.with != null) return false; + + return true; + } + + public StreamController.User[] getUsers() { + return users; + } + + @Override + public int hashCode() { + int result = users != null ? Arrays.hashCode(users) : 0; + result = 31 * result + (includeFollowingsActivity ? 1 : 0); + result = 31 * result + (includeUserChanges ? 1 : 0); + result = 31 * result + (replies != null ? replies.hashCode() : 0); + result = 31 * result + (with != null ? with.hashCode() : 0); + return result; + } + + public boolean isIncludeFollowingsActivity() { + return includeFollowingsActivity; + } + + public boolean isIncludeUserChanges() { + return includeUserChanges; + } + + public String isReplies() { + return replies; + } + + public String isWith() { + return with; + } + + @Override + public String toString() { + return "ControlStreamInfo{" + "users=" + (users == null ? null : Arrays.asList(users)) + + ", includeFollowingsActivity=" + includeFollowingsActivity + ", includeUserChanges=" + + includeUserChanges + ", replies='" + replies + '\'' + ", with='" + with + '\'' + '}'; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/FilterQuery.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/FilterQuery.java new file mode 100644 index 00000000..e6a363b7 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/FilterQuery.java @@ -0,0 +1,205 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.util.ArrayList; +import java.util.Arrays; + +import twitter4j.http.HttpParameter; +import twitter4j.internal.util.InternalStringUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +public final class FilterQuery implements java.io.Serializable { + private static final long serialVersionUID = 430966623248982833L; + private int count; + private long[] follow; + private String[] track; + private double[][] locations; + + /** + * Creates a new FilterQuery + */ + public FilterQuery() { + count = 0; + follow = null; + track = null; + locations = null; + } + + /** + * Creates a new FilterQuery + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @param follow Specifies the users, by ID, to receive public tweets from. + */ + public FilterQuery(final int count, final long[] follow) { + this(); + this.count = count; + this.follow = follow; + } + + /** + * Creates a new FilterQuery + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @param follow Specifies the users, by ID, to receive public tweets from. + * @param track Specifies keywords to track. + */ + public FilterQuery(final int count, final long[] follow, final String[] track) { + this(); + this.count = count; + this.follow = follow; + this.track = track; + } + + /** + * Creates a new FilterQuery + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @param follow Specifies the users, by ID, to receive public tweets from. + * @param track Specifies keywords to track. + * @param locations Specifies the locations to track. 2D array + */ + public FilterQuery(final int count, final long[] follow, final String[] track, final double[][] locations) { + this.count = count; + this.follow = follow; + this.track = track; + this.locations = locations; + } + + /** + * Creates a new FilterQuery + * + * @param follow Specifies the users, by ID, to receive public tweets from. + */ + public FilterQuery(final long[] follow) { + this(); + count = 0; + this.follow = follow; + } + + /** + * Sets count + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @return this instance + */ + public FilterQuery count(final int count) { + this.count = count; + return this; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final FilterQuery that = (FilterQuery) o; + + if (count != that.count) return false; + if (!Arrays.equals(follow, that.follow)) return false; + if (!Arrays.equals(track, that.track)) return false; + + return true; + } + + /** + * Sets follow + * + * @param follow Specifies the users, by ID, to receive public tweets from. + * @return this instance + */ + public FilterQuery follow(final long[] follow) { + this.follow = follow; + return this; + } + + @Override + public int hashCode() { + int result = count; + result = 31 * result + (follow != null ? Arrays.hashCode(follow) : 0); + result = 31 * result + (track != null ? Arrays.hashCode(track) : 0); + return result; + } + + /** + * Sets locations + * + * @param locations Specifies the locations to track. 2D array + * @return this instance + */ + public FilterQuery locations(final double[][] locations) { + this.locations = locations; + return this; + } + + @Override + public String toString() { + return "FilterQuery{" + "count=" + count + ", follow=" + Arrays.toString(follow) + ", track=" + + (track == null ? null : Arrays.asList(track)) + ", locations=" + + (locations == null ? null : Arrays.asList(locations)) + '}'; + } + + /** + * Sets track + * + * @param track Specifies keywords to track. + * @return this instance + */ + public FilterQuery track(final String[] track) { + this.track = track; + return this; + } + + private String toLocationsString(final double[][] keywords) { + final StringBuilder buf = new StringBuilder(20 * keywords.length * 2); + for (final double[] keyword : keywords) { + if (0 != buf.length()) { + buf.append(","); + } + buf.append(keyword[0]); + buf.append(","); + buf.append(keyword[1]); + } + return buf.toString(); + } + + /* package */HttpParameter[] asHttpParameterArray(final HttpParameter stallWarningsParam) { + final ArrayList params = new ArrayList(); + + params.add(new HttpParameter("count", count)); + if (follow != null && follow.length > 0) { + params.add(new HttpParameter("follow", InternalStringUtil.join(follow))); + } + if (track != null && track.length > 0) { + params.add(new HttpParameter("track", InternalStringUtil.join(track))); + } + if (locations != null && locations.length > 0) { + params.add(new HttpParameter("locations", toLocationsString(locations))); + } + params.add(stallWarningsParam); + final HttpParameter[] paramArray = new HttpParameter[params.size()]; + return params.toArray(paramArray); + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/RawStreamListener.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/RawStreamListener.java new file mode 100644 index 00000000..beb1f16c --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/RawStreamListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 3.0.2 + */ +public interface RawStreamListener extends StreamListener { + void onMessage(String rawString); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsAdapter.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsAdapter.java new file mode 100644 index 00000000..6287c2ec --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsAdapter.java @@ -0,0 +1,95 @@ +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +public class SiteStreamsAdapter implements SiteStreamsListener { + @Override + public void onBlock(final long forUser, final User source, final User blockedUser) { + } + + @Override + public void onDeletionNotice(final long forUser, final long directMessageId, final long userId) { + } + + @Override + public void onDeletionNotice(final long forUser, final StatusDeletionNotice statusDeletionNotice) { + } + + @Override + public void onDirectMessage(final long forUser, final DirectMessage directMessage) { + } + + @Override + public void onDisconnectionNotice(final String screenName) { + } + + @Override + public void onException(final Exception ex) { + } + + @Override + public void onFavorite(final long forUser, final User source, final User target, final Status favoritedStatus) { + } + + @Override + public void onFollow(final long forUser, final User source, final User followedUser) { + } + + @Override + public void onFriendList(final long forUser, final long[] friendIds) { + } + + @Override + public void onStatus(final long forUser, final Status status) { + } + + @Override + public void onUnblock(final long forUser, final User source, final User unblockedUser) { + } + + @Override + public void onUnfavorite(final long forUser, final User source, final User target, final Status unfavoritedStatus) { + } + + @Override + public void onUnfollow(final long forUser, final User source, final User followedUser) { + } + + @Override + public void onUserListCreation(final long forUser, final User listOwner, final UserList list) { + } + + @Override + public void onUserListDeletion(final long forUser, final User listOwner, final UserList list) { + } + + @Override + public void onUserListMemberAddition(final long forUser, final User addedUser, final User listOwner, + final UserList list) { + } + + @Override + public void onUserListMemberDeletion(final long forUser, final User deletedUser, final User listOwner, + final UserList list) { + } + + @Override + public void onUserListSubscription(final long forUser, final User subscriber, final User listOwner, + final UserList list) { + } + + @Override + public void onUserListUnsubscription(final long forUser, final User subscriber, final User listOwner, + final UserList list) { + } + + @Override + public void onUserListUpdate(final long forUser, final User listOwner, final UserList list) { + } + + @Override + public void onUserProfileUpdate(final long forUser, final User updatedUser) { + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsImpl.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsImpl.java new file mode 100755 index 00000000..ca492568 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsImpl.java @@ -0,0 +1,281 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.IOException; +import java.io.InputStream; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.conf.StreamConfiguration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.async.Dispatcher; +import twitter4j.internal.util.InternalParseUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +class SiteStreamsImpl extends StatusStreamBase { + + private final StreamController cs; + + private static ThreadLocal forUser = new ThreadLocal() { + @Override + protected Integer initialValue() { + return 0; + } + }; + + protected static final RawStreamListener[] EMPTY = new RawStreamListener[0]; + + /* package */SiteStreamsImpl(final Dispatcher dispatcher, final HttpResponse response, + final StreamConfiguration conf, final StreamController cs) throws IOException { + super(dispatcher, response, conf); + this.cs = cs; + } + + /* package */SiteStreamsImpl(final Dispatcher dispatcher, final InputStream stream, final StreamConfiguration conf, + final StreamController cs) throws IOException { + super(dispatcher, stream, conf); + this.cs = cs; + } + + @Override + public void next(final StatusListener listener) throws TwitterException { + handleNextElement(new StatusListener[] { listener }, EMPTY); + } + + @Override + public void next(final StreamListener[] listeners, final RawStreamListener[] rawStreamListeners) + throws TwitterException { + handleNextElement(listeners, rawStreamListeners); + } + + @Override + public void onDisconnectionNotice(final String line, final StreamListener[] listeners) { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onDisconnectionNotice(line); + } + } + + @Override + public void onException(final Exception ex, final StreamListener[] listeners) { + for (final StreamListener listener : listeners) { + listener.onException(ex); + } + } + + @Override + protected void onBlock(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onBlock(forUser.get(), asUser(source), asUser(target)); + } + } + + @Override + protected void onDelete(final JSONObject json, final StreamListener[] listeners) throws JSONException { + final JSONObject deletionNotice = json.getJSONObject("delete"); + if (deletionNotice.has("status")) { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onDeletionNotice(forUser.get(), new StatusDeletionNoticeImpl( + deletionNotice.getJSONObject("status"))); + } + } else { + final JSONObject directMessage = deletionNotice.getJSONObject("direct_message"); + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onDeletionNotice(forUser.get(), + InternalParseUtil.getInt("id", directMessage), + InternalParseUtil.getLong("user_id", directMessage)); + } + } + } + + @Override + protected void onDirectMessage(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onDirectMessage(forUser.get(), asDirectMessage(json)); + } + } + + @Override + protected void onFavorite(final JSONObject source, final JSONObject target, final JSONObject targetObject, + final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onFavorite(forUser.get(), asUser(source), asUser(target), + asStatus(targetObject)); + } + } + + @Override + protected void onFollow(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onFollow(forUser.get(), asUser(source), asUser(target)); + } + } + + @Override + protected void onFriends(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onFriendList(forUser.get(), asFriendList(json)); + } + } + + @Override + protected void onMessage(final String rawString, final RawStreamListener[] listeners) throws TwitterException { + for (final RawStreamListener listener : listeners) { + listener.onMessage(rawString); + } + } + + @Override + protected void onStatus(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onStatus(forUser.get(), asStatus(json)); + } + } + + @Override + protected void onUnblock(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUnblock(forUser.get(), asUser(source), asUser(target)); + } + } + + @Override + protected void onUnfavorite(final JSONObject source, final JSONObject target, final JSONObject targetObject, + final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUnfavorite(forUser.get(), asUser(source), asUser(target), + asStatus(targetObject)); + } + } + + @Override + protected void onUnfollow(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUnfollow(forUser.get(), asUser(source), asUser(target)); + } + } + + @Override + protected void onUserListCreation(final JSONObject source, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListCreation(forUser.get(), asUser(source), asUserList(userList)); + } + } + + @Override + protected void onUserListDestroyed(final JSONObject source, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListDeletion(forUser.get(), asUser(source), asUserList(userList)); + } + } + + @Override + protected void onUserListMemberAddition(final JSONObject addedMember, final JSONObject owner, + final JSONObject userList, final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListMemberAddition(forUser.get(), asUser(addedMember), + asUser(owner), asUserList(userList)); + } + } + + @Override + protected void onUserListMemberDeletion(final JSONObject deletedMember, final JSONObject owner, + final JSONObject userList, final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListMemberDeletion(forUser.get(), asUser(deletedMember), + asUser(owner), asUserList(userList)); + } + } + + @Override + protected void onUserListSubscription(final JSONObject source, final JSONObject owner, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListSubscription(forUser.get(), asUser(source), asUser(owner), + asUserList(userList)); + } + } + + @Override + protected void onUserListUnsubscription(final JSONObject source, final JSONObject owner, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListUnsubscription(forUser.get(), asUser(source), asUser(owner), + asUserList(userList)); + } + } + + @Override + protected void onUserListUpdated(final JSONObject source, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserListUpdate(forUser.get(), asUser(source), asUserList(userList)); + } + } + + @Override + protected void onUserUpdate(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((SiteStreamsListener) listener).onUserProfileUpdate(forUser.get(), asUser(source)); + } + } + + @Override + protected String parseLine(final String line) { + if ("".equals(line) || null == line) return line; + final int userIdEnd = line.indexOf(',', 12); + // in the documentation for_user is not quoted, but actually it is + // quoted + if (cs.getControlURI() == null && line.charAt(2) == 'c' && line.charAt(3) == 'o' && line.charAt(4) == 'n') { + // control endpoint uri + // https://dev.twitter.com/docs/streaming-api/control-streams + JSONObject control = null; + try { + control = new JSONObject(line); + cs.setControlURI(CONF.getSiteStreamBaseURL() + + control.getJSONObject("control").getString("control_uri")); + logger.info("control_uri: " + cs.getControlURI()); + } catch (final JSONException e) { + logger.warn("received unexpected event:" + line); + } + return null; + } + + if (line.charAt(2) == 'd') // disconnection notice + // {"disconnect":{"code":3,"stream_name":"yusuke-sitestream6139-yusuke","reason":"control request for yusuke-sitestream6139 106.171.17.29 /1.1/site.json sitestream"}} + return line; + if (line.charAt(12) == '"') { + forUser.set(Integer.parseInt(line.substring(13, userIdEnd - 1))); + } else { + forUser.set(Integer.parseInt(line.substring(12, userIdEnd))); + } + return line.substring(userIdEnd + 11, line.length() - 1); + } + +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsListener.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsListener.java new file mode 100644 index 00000000..33a91109 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/SiteStreamsListener.java @@ -0,0 +1,156 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +public interface SiteStreamsListener extends StreamListener { + /** + * @param forUser the user id to whom sent the event + * @param source + * @param blockedUser + */ + void onBlock(long forUser, User source, User blockedUser); + + void onDeletionNotice(long forUser, long directMessageId, long userId); + + void onDeletionNotice(long forUser, StatusDeletionNotice statusDeletionNotice); + + /** + * @param forUser the user id to whom sent the event + * @param directMessage + */ + void onDirectMessage(long forUser, DirectMessage directMessage); + + /** + * callback method for {@link twitter4j.StreamController#removeUsers(long[])} + */ + void onDisconnectionNotice(String line); + + @Override + void onException(Exception ex); + + /** + * @param forUser the user id to whom sent the event + * @param source + * @param target + * @param favoritedStatus + */ + void onFavorite(long forUser, User source, User target, Status favoritedStatus); + + /** + * @param forUser the user id to whom sent the event + * @param source + * @param followedUser + */ + void onFollow(long forUser, User source, User followedUser); + + /** + * @param forUser the user id to whom sent the event + * @param friendIds + */ + void onFriendList(long forUser, long[] friendIds); + + void onStatus(long forUser, Status status); + + /** + * @param forUser the user id to whom sent the event + * @param source + * @param unblockedUser + */ + void onUnblock(long forUser, User source, User unblockedUser); + + /** + * @param forUser the user id to whom sent the event + * @param target + * @param unfavoritedStatus + */ + void onUnfavorite(long forUser, User source, User target, Status unfavoritedStatus); + + /** + * @param forUser the user id to whom sent the event + * @param source + * @param unfollowedUser + * @since Twitter4J 2.1.11 + */ + void onUnfollow(long forUser, User source, User unfollowedUser); + + /** + * @param forUser the user id to whom sent the event + * @param listOwner + * @param list + */ + void onUserListCreation(long forUser, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param listOwner + * @param list + */ + void onUserListDeletion(long forUser, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param addedMember + * @param listOwner + * @param list + */ + void onUserListMemberAddition(long forUser, User addedMember, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param deletedMember + * @param listOwner + * @param list + */ + void onUserListMemberDeletion(long forUser, User deletedMember, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param subscriber + * @param listOwner + * @param list + */ + void onUserListSubscription(long forUser, User subscriber, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param subscriber + * @param listOwner + * @param list + */ + void onUserListUnsubscription(long forUser, User subscriber, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param listOwner + * @param list + */ + void onUserListUpdate(long forUser, User listOwner, UserList list); + + /** + * @param forUser the user id to whom sent the event + * @param updatedUser updated user + * @since Twitter4J 2.1.9 + */ + void onUserProfileUpdate(long forUser, User updatedUser); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StallWarning.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StallWarning.java new file mode 100644 index 00000000..15926a6e --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StallWarning.java @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * Copyright (C) 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package twitter4j; + +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +import java.io.Serializable; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * @author Yusuke Yamamoto - yusuke at twitter.com + * @since Twitter4J 3.0.0 + */ +public final class StallWarning implements Serializable { + private static final long serialVersionUID = 7387184309206228363L; + private final String code; + private final String message; + private final int percentFull; + + StallWarning(final JSONObject json) throws JSONException { + final JSONObject warning = json.getJSONObject("warning"); + code = getRawString("code", warning); + message = getRawString("message", warning); + percentFull = getInt("percent_full", warning); + + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final StallWarning that = (StallWarning) o; + + if (percentFull != that.percentFull) return false; + if (code != null ? !code.equals(that.code) : that.code != null) return false; + if (message != null ? !message.equals(that.message) : that.message != null) return false; + + return true; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public int getPercentFull() { + return percentFull; + } + + @Override + public int hashCode() { + int result = code != null ? code.hashCode() : 0; + result = 31 * result + (message != null ? message.hashCode() : 0); + result = 31 * result + percentFull; + return result; + } + + @Override + public String toString() { + return "StallWarning{" + "code='" + code + '\'' + ", message='" + message + '\'' + ", percentFull=" + + percentFull + '}'; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusAdapter.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusAdapter.java new file mode 100644 index 00000000..c154e9f5 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusAdapter.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +public class StatusAdapter implements StatusListener { + @Override + public void onDeletionNotice(final StatusDeletionNotice statusDeletionNotice) { + } + + @Override + public void onException(final Exception ex) { + } + + @Override + public void onScrubGeo(final long userId, final long upToStatusId) { + } + + @Override + public void onStallWarning(final StallWarning warning) { + } + + @Override + public void onStatus(final Status status) { + } + + @Override + public void onTrackLimitationNotice(final int numberOfLimitedStatuses) { + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusDeletionNotice.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusDeletionNotice.java new file mode 100644 index 00000000..e93d1ca2 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusDeletionNotice.java @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * A data class representing Status deletionNotice
+ * Clients are urged to honor deletionNotice requests and discard deleted + * statuses immediately. At times, status deletionNotice messages may arrive + * before the status. Even in this case, the late arriving status should be + * deleted from your backing store. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.0 + */ +public interface StatusDeletionNotice extends Comparable, java.io.Serializable { + long getStatusId(); + + long getUserId(); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusDeletionNoticeImpl.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusDeletionNoticeImpl.java new file mode 100644 index 00000000..4853ffa1 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusDeletionNoticeImpl.java @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import org.json.JSONObject; + +import twitter4j.internal.util.InternalParseUtil; + +/** + * StatusDeletionNotice implementation. This class is NOT intended to be + * extended but left non-final for the ease of mock testing. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +class StatusDeletionNoticeImpl implements StatusDeletionNotice, java.io.Serializable { + + private final long statusId; + private final long userId; + private static final long serialVersionUID = 1723338404242596062L; + + /* package */StatusDeletionNoticeImpl(final JSONObject status) { + statusId = InternalParseUtil.getLong("id", status); + userId = InternalParseUtil.getLong("user_id", status); + } + + @Override + public int compareTo(final StatusDeletionNotice that) { + final long delta = statusId - that.getStatusId(); + if (delta < Integer.MIN_VALUE) + return Integer.MIN_VALUE; + else if (delta > Integer.MAX_VALUE) return Integer.MAX_VALUE; + return (int) delta; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final StatusDeletionNoticeImpl that = (StatusDeletionNoticeImpl) o; + + if (statusId != that.statusId) return false; + if (userId != that.userId) return false; + + return true; + } + + @Override + public long getStatusId() { + return statusId; + } + + @Override + public long getUserId() { + return userId; + } + + @Override + public int hashCode() { + int result = (int) (statusId ^ statusId >>> 32); + result = 31 * result + (int) (userId ^ userId >>> 32); + return result; + } + + @Override + public String toString() { + return "StatusDeletionNoticeImpl{" + "statusId=" + statusId + ", userId=" + userId + '}'; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusListener.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusListener.java new file mode 100644 index 00000000..4e146a70 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusListener.java @@ -0,0 +1,86 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.4 + */ +public interface StatusListener extends StreamListener { + /** + * Called upon deletionNotice notices. Clients are urged to honor + * deletionNotice requests and discard deleted statuses immediately. At + * times, status deletionNotice messages may arrive before the status. Even + * in this case, the late arriving status should be deleted from your + * backing store. + * + * @param statusDeletionNotice the deletionNotice notice + * @see Streaming + * API Concepts | Twitter Developers + * @since Twitter4J 2.1.0 + */ + void onDeletionNotice(StatusDeletionNotice statusDeletionNotice); + + /** + * Called upon location deletion messages. Clients are urged to honor + * deletion requests and remove appropriate geolocation information from + * both the display and your backing store immediately. Note that in some + * cases the location deletion message may arrive before a tweet that lies + * within the deletion range arrives. You should still strip the location + * data. + * + * @param userId user id + * @param upToStatusId up to status id + * @since Twitter4J 2.1.9 + */ + void onScrubGeo(long userId, long upToStatusId); + + /** + * Called when receiving stall warnings. + * + * @param warning StallWaning + * @see Streaming + * API request parameters - stall_warnings + * @since Twitter4J 3.0.0 + */ + void onStallWarning(StallWarning warning); + + void onStatus(Status status); + + /** + * This notice will be sent each time a limited stream becomes unlimited.
+ * If this number is high and or rapidly increasing, it is an indication + * that your predicate is too broad, and you should consider a predicate + * with higher selectivity. + * + * @param numberOfLimitedStatuses an enumeration of statuses that matched + * the track predicate but were administratively limited. + * @see Streaming + * API Concepts - Filter Limiting | Twitter Developers + * @see Streaming + * API Concepts - Parsing Responses | Twitter Developers + * @see Twitter + * Development Talk - Track API Limit message meaning + * @since Twitter4J 2.1.0 + */ + void onTrackLimitationNotice(int numberOfLimitedStatuses); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStream.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStream.java new file mode 100644 index 00000000..18065bb0 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStream.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.IOException; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.4 + */ +public interface StatusStream { + + void close() throws IOException; + + /** + * Reads next status from this stream. + * + * @param listener a StatusListener implementation + * @throws TwitterException when the end of the stream has been reached. + * @throws IllegalStateException when the end of the stream had been + * reached. + */ + void next(StatusListener listener) throws TwitterException; +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStreamBase.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStreamBase.java new file mode 100755 index 00000000..27bb14f8 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStreamBase.java @@ -0,0 +1,418 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.conf.StreamConfiguration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.async.Dispatcher; +import twitter4j.internal.json.DataObjectFactoryUtil; +import twitter4j.internal.json.InternalJSONFactory; +import twitter4j.internal.json.InternalJSONFactoryImpl; +import twitter4j.internal.logging.Logger; +import twitter4j.json.JSONObjectType; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +abstract class StatusStreamBase implements StatusStream { + protected static final Logger logger = Logger.getLogger(StatusStreamImpl.class); + + private boolean streamAlive = true; + private final BufferedReader br; + private final InputStream is; + private HttpResponse response; + protected final Dispatcher dispatcher; + protected final StreamConfiguration CONF; + protected InternalJSONFactory factory; + + /* package */ + + StatusStreamBase(final Dispatcher dispatcher, final HttpResponse response, final StreamConfiguration conf) + throws IOException { + this(dispatcher, response.asStream(), conf); + this.response = response; + } + + StatusStreamBase(final Dispatcher dispatcher, final InputStream stream, final StreamConfiguration conf) + throws IOException { + is = stream; + br = new BufferedReader(new InputStreamReader(stream, "UTF-8")); + this.dispatcher = dispatcher; + CONF = conf; + factory = new InternalJSONFactoryImpl(conf); + } + + /* package */ + + @Override + public void close() throws IOException { + streamAlive = false; + is.close(); + br.close(); + if (response != null) { + response.disconnect(); + } + } + + @Override + public abstract void next(StatusListener listener) throws TwitterException; + + public abstract void next(StreamListener[] listeners, RawStreamListener[] rawStreamListeners) + throws TwitterException; + + public void onException(final Exception e, final StreamListener[] listeners, + final RawStreamListener[] rawStreamListeners) { + for (final StreamListener listener : listeners) { + listener.onException(e); + } + for (final RawStreamListener listener : rawStreamListeners) { + listener.onException(e); + } + } + + protected DirectMessage asDirectMessage(final JSONObject json) throws TwitterException { + DirectMessage directMessage; + try { + directMessage = factory.createDirectMessage(json.getJSONObject("direct_message")); + } catch (final JSONException e) { + throw new TwitterException(e); + } + if (CONF.isJSONStoreEnabled()) { + DataObjectFactoryUtil.registerJSONObject(directMessage, json); + } + return directMessage; + } + + protected long[] asFriendList(final JSONObject json) throws TwitterException { + JSONArray friends; + try { + friends = json.getJSONArray("friends"); + final long[] friendIds = new long[friends.length()]; + for (int i = 0; i < friendIds.length; ++i) { + friendIds[i] = Long.parseLong(friends.getString(i)); + } + return friendIds; + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + protected Status asStatus(final JSONObject json) throws TwitterException { + final Status status = factory.createStatus(json); + if (CONF.isJSONStoreEnabled()) { + DataObjectFactoryUtil.registerJSONObject(status, json); + } + return status; + } + + protected User asUser(final JSONObject json) throws TwitterException { + final User user = factory.createUser(json); + if (CONF.isJSONStoreEnabled()) { + DataObjectFactoryUtil.registerJSONObject(user, json); + } + return user; + } + + protected UserList asUserList(final JSONObject json) throws TwitterException { + final UserList userList = factory.createAUserList(json); + if (CONF.isJSONStoreEnabled()) { + DataObjectFactoryUtil.registerJSONObject(userList, json); + } + return userList; + } + + protected void handleNextElement(final StreamListener[] listeners, final RawStreamListener[] rawStreamListeners) + throws TwitterException { + if (!streamAlive) throw new IllegalStateException("Stream already closed."); + try { + final String line = br.readLine(); + if (null == line) // invalidate this status stream + throw new IOException("the end of the stream has been reached"); + dispatcher.invokeLater(new StreamEvent(line) { + @Override + public void run() { + try { + if (rawStreamListeners.length > 0) { + onMessage(line, rawStreamListeners); + } + // SiteStreamsImpl will parse "forUser" attribute + line = parseLine(line); + if (line != null && line.length() > 0) { + // parsing JSON is an expensive process and can be + // avoided when all listeners are instanceof + // RawStreamListener + if (listeners.length > 0) { + if (CONF.isJSONStoreEnabled()) { + DataObjectFactoryUtil.clearThreadLocalMap(); + } + final JSONObject json = new JSONObject(line); + final JSONObjectType.Type event = JSONObjectType.determine(json); + if (logger.isDebugEnabled()) { + logger.debug("Received:", + CONF.isPrettyDebugEnabled() ? json.toString(1) : json.toString()); + } + switch (event) { + case SENDER: + onSender(json, listeners); + break; + case STATUS: + onStatus(json, listeners); + break; + case DIRECT_MESSAGE: + onDirectMessage(json, listeners); + break; + case DELETE: + onDelete(json, listeners); + break; + case LIMIT: + onLimit(json, listeners); + break; + case STALL_WARNING: + onStallWarning(json, listeners); + break; + case SCRUB_GEO: + onScrubGeo(json, listeners); + break; + case FRIENDS: + onFriends(json, listeners); + break; + case FAVORITE: + onFavorite(json.getJSONObject("source"), json.getJSONObject("target"), + json.getJSONObject("target_object"), listeners); + break; + case UNFAVORITE: + onUnfavorite(json.getJSONObject("source"), json.getJSONObject("target"), + json.getJSONObject("target_object"), listeners); + break; + case FOLLOW: + onFollow(json.getJSONObject("source"), json.getJSONObject("target"), listeners); + break; + case UNFOLLOW: + onUnfollow(json.getJSONObject("source"), json.getJSONObject("target"), + listeners); + break; + case USER_LIST_MEMBER_ADDED: + onUserListMemberAddition(json.getJSONObject("target"), + json.getJSONObject("source"), json.getJSONObject("target_object"), + listeners); + break; + case USER_LIST_MEMBER_DELETED: + onUserListMemberDeletion(json.getJSONObject("target"), + json.getJSONObject("source"), json.getJSONObject("target_object"), + listeners); + break; + case USER_LIST_SUBSCRIBED: + onUserListSubscription(json.getJSONObject("source"), + json.getJSONObject("target"), json.getJSONObject("target_object"), + listeners); + break; + case USER_LIST_UNSUBSCRIBED: + onUserListUnsubscription(json.getJSONObject("source"), + json.getJSONObject("target"), json.getJSONObject("target_object"), + listeners); + break; + case USER_LIST_CREATED: + onUserListCreation(json.getJSONObject("source"), json.getJSONObject("target"), + listeners); + break; + case USER_LIST_UPDATED: + onUserListUpdated(json.getJSONObject("source"), json.getJSONObject("target"), + listeners); + break; + case USER_LIST_DESTROYED: + onUserListDestroyed(json.getJSONObject("source"), json.getJSONObject("target"), + listeners); + break; + case USER_UPDATE: + onUserUpdate(json.getJSONObject("source"), json.getJSONObject("target"), + listeners); + break; + case BLOCK: + onBlock(json.getJSONObject("source"), json.getJSONObject("target"), listeners); + break; + case UNBLOCK: + onUnblock(json.getJSONObject("source"), json.getJSONObject("target"), listeners); + break; + case DISCONNECTION: + onDisconnectionNotice(line, listeners); + break; + case UNKNOWN: + default: + logger.warn("Received unknown event:", + CONF.isPrettyDebugEnabled() ? json.toString(1) : json.toString()); + } + } + } + } catch (final Exception ex) { + onException(ex, listeners); + } + } + }); + + } catch (final IOException ioe) { + try { + is.close(); + } catch (final IOException ignore) { + } + final boolean isUnexpectedException = streamAlive; + streamAlive = false; + if (isUnexpectedException) throw new TwitterException("Stream closed.", ioe); + } + } + + protected void onBlock(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + logger.warn("Unhandled event: onBlock"); + } + + protected void onDelete(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + logger.warn("Unhandled event: onDelete"); + } + + protected void onDirectMessage(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + logger.warn("Unhandled event: onDirectMessage"); + } + + protected void onDisconnectionNotice(final String line, final StreamListener[] listeners) { + logger.warn("Unhandled event: ", line); + } + + protected void onException(final Exception e, final StreamListener[] listeners) { + logger.warn("Unhandled event: ", e.getMessage()); + } + + protected void onFavorite(final JSONObject source, final JSONObject target, final JSONObject targetObject, + final StreamListener[] listeners) throws TwitterException { + logger.warn("Unhandled event: onFavorite"); + } + + protected void onFollow(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + logger.warn("Unhandled event: onFollow"); + } + + protected void onFriends(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + logger.warn("Unhandled event: onFriends"); + } + + protected void onLimit(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + logger.warn("Unhandled event: onLimit"); + } + + protected void onMessage(final String rawString, final RawStreamListener[] listeners) throws TwitterException { + logger.warn("Unhandled event: onMessage"); + } + + protected void onScrubGeo(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + logger.warn("Unhandled event: onScrubGeo"); + } + + protected void onSender(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + logger.warn("Unhandled event: onSender"); + } + + protected void onStallWarning(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + logger.warn("Unhandled event: onStallWarning"); + } + + protected void onStatus(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + logger.warn("Unhandled event: onStatus"); + } + + protected void onUnblock(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + logger.warn("Unhandled event: onUnblock"); + } + + protected void onUnfavorite(final JSONObject source, final JSONObject target, final JSONObject targetObject, + final StreamListener[] listeners) throws TwitterException { + logger.warn("Unhandled event: onUnfavorite"); + } + + protected void onUnfollow(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + logger.warn("Unhandled event: onUnfollow"); + } + + protected void onUserListCreation(final JSONObject source, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + logger.warn("Unhandled event: onUserListCreation"); + } + + protected void onUserListDestroyed(final JSONObject source, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException { + logger.warn("Unhandled event: onUserListDestroyed"); + } + + protected void onUserListMemberAddition(final JSONObject addedMember, final JSONObject owner, + final JSONObject userList, final StreamListener[] listeners) throws TwitterException, JSONException { + logger.warn("Unhandled event: onUserListMemberAddition"); + } + + protected void onUserListMemberDeletion(final JSONObject deletedMember, final JSONObject owner, + final JSONObject userList, final StreamListener[] listeners) throws TwitterException, JSONException { + logger.warn("Unhandled event: onUserListMemberDeletion"); + } + + protected void onUserListSubscription(final JSONObject source, final JSONObject owner, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + logger.warn("Unhandled event: onUserListSubscription"); + } + + protected void onUserListUnsubscription(final JSONObject source, final JSONObject owner, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + logger.warn("Unhandled event: onUserListUnsubscription"); + } + + protected void onUserListUpdated(final JSONObject source, final JSONObject userList, + final StreamListener[] listeners) throws TwitterException, JSONException { + logger.warn("Unhandled event: onUserListUpdated"); + } + + protected void onUserUpdate(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + logger.warn("Unhandled event: onUserUpdate"); + } + + protected String parseLine(final String line) { + return line; + } + + abstract class StreamEvent implements Runnable { + String line; + + StreamEvent(final String line) { + this.line = line; + } + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStreamImpl.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStreamImpl.java new file mode 100644 index 00000000..ec3da949 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StatusStreamImpl.java @@ -0,0 +1,136 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.IOException; +import java.io.InputStream; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.conf.StreamConfiguration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.async.Dispatcher; +import twitter4j.internal.util.InternalParseUtil; + +/** + * StatusStream implementation. This class is NOT intended to be extended but + * left non-final for the ease of mock testing. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +class StatusStreamImpl extends StatusStreamBase { + /* package */ + + protected String line; + + protected static final RawStreamListener[] EMPTY = new RawStreamListener[0]; + + StatusStreamImpl(final Dispatcher dispatcher, final HttpResponse response, final StreamConfiguration conf) + throws IOException { + super(dispatcher, response, conf); + } + + StatusStreamImpl(final Dispatcher dispatcher, final InputStream stream, final StreamConfiguration conf) + throws IOException { + super(dispatcher, stream, conf); + } + + /* package */ + @Override + public void next(final StatusListener listener) throws TwitterException { + handleNextElement(new StatusListener[] { listener }, EMPTY); + } + + @Override + public void next(final StreamListener[] listeners, final RawStreamListener[] rawStreamListeners) + throws TwitterException { + handleNextElement(listeners, rawStreamListeners); + } + + @Override + public void onException(final Exception e, final StreamListener[] listeners) { + for (final StreamListener listener : listeners) { + listener.onException(e); + } + } + + @Override + protected void onDelete(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + for (final StreamListener listener : listeners) { + final JSONObject deletionNotice = json.getJSONObject("delete"); + if (deletionNotice.has("status")) { + ((StatusListener) listener).onDeletionNotice(new StatusDeletionNoticeImpl(deletionNotice + .getJSONObject("status"))); + } else { + final JSONObject directMessage = deletionNotice.getJSONObject("direct_message"); + ((UserStreamListener) listener).onDeletionNotice(InternalParseUtil.getLong("id", directMessage), + InternalParseUtil.getLong("user_id", directMessage)); + } + } + } + + @Override + protected void onLimit(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + for (final StreamListener listener : listeners) { + ((StatusListener) listener).onTrackLimitationNotice(InternalParseUtil.getInt("track", + json.getJSONObject("limit"))); + } + } + + @Override + protected void onMessage(final String rawString, final RawStreamListener[] listeners) throws TwitterException { + for (final RawStreamListener listener : listeners) { + listener.onMessage(rawString); + } + } + + @Override + protected void onScrubGeo(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + final JSONObject scrubGeo = json.getJSONObject("scrub_geo"); + for (final StreamListener listener : listeners) { + ((StatusListener) listener).onScrubGeo(InternalParseUtil.getLong("user_id", scrubGeo), + InternalParseUtil.getLong("up_to_status_id", scrubGeo)); + } + + } + + @Override + protected void onStallWarning(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + for (final StreamListener listener : listeners) { + ((StatusListener) listener).onStallWarning(new StallWarning(json)); + } + } + + @Override + protected void onStatus(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((StatusListener) listener).onStatus(asStatus(json)); + } + } + + @Override + protected String parseLine(final String line) { + this.line = line; + return line; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamController.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamController.java new file mode 100644 index 00000000..110436ab --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamController.java @@ -0,0 +1,270 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * Copyright (C) 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package twitter4j; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +import java.io.Serializable; +import java.util.Arrays; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.auth.Authorization; +import twitter4j.auth.AuthorizationFactory; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpClientWrapper; +import twitter4j.http.HttpParameter; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; +import twitter4j.internal.util.InternalStringUtil; + +/** + * @author Yusuke Yamamoto - yusuke at twitter.com + * @since Twitter4J 2.2.6 + */ +public class StreamController { + private String controlURI = null; + private final HttpClientWrapper HTTP; + private final Authorization AUTH; + + Object lock = new Object(); + + /* package */StreamController(final Configuration conf) { + HTTP = new HttpClientWrapper(conf); + AUTH = AuthorizationFactory.getInstance(conf); + } + + /* package */StreamController(final HttpClientWrapper http, final Authorization auth) { + HTTP = http; + AUTH = auth; + } + + public String addUsers(final long[] userIds) throws TwitterException { + ensureControlURISet(); + final HttpParameter param = new HttpParameter("user_id", InternalStringUtil.join(userIds)); + final HttpResponse res = HTTP.post(controlURI + "/add_user.json", controlURI + "/add_user.json", + new HttpParameter[] { param }, AUTH); + return res.asString(); + } + + public FriendsIDs getFriendsIDs(final long userId, final long cursor) throws TwitterException { + ensureControlURISet(); + final HttpResponse res = HTTP + .post(controlURI + "/friends/ids.json", controlURI + "/friends/ids.json", new HttpParameter[] { + new HttpParameter("user_id", userId), new HttpParameter("cursor", cursor) }, AUTH); + return new FriendsIDs(res); + } + + public ControlStreamInfo getInfo() throws TwitterException { + ensureControlURISet(); + final HttpResponse res = HTTP.get(controlURI + "/info.json", controlURI + "/info.json", AUTH); + return new ControlStreamInfo(this, res.asJSONObject()); + } + + public String removeUsers(final long[] userIds) throws TwitterException { + ensureControlURISet(); + final HttpParameter param = new HttpParameter("user_id", InternalStringUtil.join(userIds)); + final HttpResponse res = HTTP.post(controlURI + "/remove_user.json", controlURI + "/remove_user.json", + new HttpParameter[] { param }, AUTH); + return res.asString(); + } + + /* package */User createUser(final JSONObject json) { + return new User(json); + } + + void ensureControlURISet() throws TwitterException { + synchronized (lock) { + try { + while (controlURI == null) { + lock.wait(30000); + throw new TwitterException("timed out for control uri to be ready"); + } + } catch (final InterruptedException e) { + } + } + } + + String getControlURI() { + return controlURI; + } + + void setControlURI(final String controlURI) { + this.controlURI = controlURI.replace("/1.1//1.1/", "/1.1/"); + synchronized (lock) { + lock.notifyAll(); + } + } + + public final class FriendsIDs implements CursorSupport, Serializable { + private static final long serialVersionUID = -6282978710522199102L; + private long[] ids; + private long previousCursor = -1; + private long nextCursor = -1; + private User user; + + /* package */FriendsIDs(final HttpResponse res) throws TwitterException { + init(res.asJSONObject()); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final FriendsIDs that = (FriendsIDs) o; + + if (nextCursor != that.nextCursor) return false; + if (previousCursor != that.previousCursor) return false; + if (!Arrays.equals(ids, that.ids)) return false; + if (user != null ? !user.equals(that.user) : that.user != null) return false; + + return true; + } + + public long[] getIds() { + return ids; + } + + /** + * {@inheritDoc} + */ + @Override + public long getNextCursor() { + return nextCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public long getPreviousCursor() { + return previousCursor; + } + + public User getUser() { + return user; + } + + @Override + public int hashCode() { + int result = ids != null ? Arrays.hashCode(ids) : 0; + result = 31 * result + (int) (previousCursor ^ previousCursor >>> 32); + result = 31 * result + (int) (nextCursor ^ nextCursor >>> 32); + result = 31 * result + (user != null ? user.hashCode() : 0); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasNext() { + return 0 != nextCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasPrevious() { + return 0 != previousCursor; + } + + @Override + public String toString() { + return "FriendsIDs{" + "ids=" + ids + ", previousCursor=" + previousCursor + ", nextCursor=" + nextCursor + + ", user=" + user + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + final JSONObject follow = json.getJSONObject("follow"); + final JSONArray idList = follow.getJSONArray("friends"); + ids = new long[idList.length()]; + for (int i = 0; i < idList.length(); i++) { + try { + ids[i] = Long.parseLong(idList.getString(i)); + } catch (final NumberFormatException nfe) { + throw new TwitterException("Twitter API returned malformed response: " + json, nfe); + } + } + user = new User(follow.getJSONObject("user")); + previousCursor = InternalParseUtil.getLong("previous_cursor", json); + nextCursor = InternalParseUtil.getLong("next_cursor", json); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + } + + public final class User implements Serializable { + private static final long serialVersionUID = -2925833063500478073L; + private final long id; + private final String name; + private final boolean dm; + + /* package */User(final JSONObject json) { + id = getLong("id", json); + name = getRawString("name", json); + dm = getBoolean("dm", json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final User user = (User) o; + + if (dm != user.dm) return false; + if (id != user.id) return false; + if (name != null ? !name.equals(user.name) : user.name != null) return false; + + return true; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + int result = (int) (id ^ id >>> 32); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (dm ? 1 : 0); + return result; + } + + public boolean isDMAccessible() { + return dm; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name='" + name + '\'' + ", dm=" + dm + '}'; + } + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamImplementation.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamImplementation.java new file mode 100644 index 00000000..85f2d1ad --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamImplementation.java @@ -0,0 +1,15 @@ +package twitter4j; + +import java.io.IOException; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +interface StreamImplementation { + void close() throws IOException; + + void next(StreamListener[] listeners, RawStreamListener[] rawStreamListeners) throws TwitterException; + + void onException(Exception ex, StreamListener[] listeners, RawStreamListener[] rawStreamListeners); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamListener.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamListener.java new file mode 100644 index 00000000..463cf929 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/StreamListener.java @@ -0,0 +1,25 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +interface StreamListener { + void onException(Exception ex); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStream.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStream.java new file mode 100755 index 00000000..d07b61d5 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStream.java @@ -0,0 +1,373 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package twitter4j; + +import twitter4j.auth.OAuthSupport; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.0 + */ +public interface TwitterStream extends OAuthSupport, TwitterBase { + /** + * Adds a ConnectionLifeCycleListener + * + * @param listener listener to be added + * @since Twitter4J 2.1.7 + */ + void addConnectionLifeCycleListener(ConnectionLifeCycleListener listener); + + /** + * @param listener listener to add + * @since Twitter4J 3.0.2 + */ + void addListener(RawStreamListener listener); + + /** + * @param listener listener to add + * @since Twitter4J 2.1.8 + */ + void addListener(SiteStreamsListener listener); + + /** + * @param listener listener to add + * @since Twitter4J 2.1.8 + */ + void addListener(StatusListener listener); + + /** + * @param listener listener to add + * @since Twitter4J 2.1.8 + */ + void addListener(UserStreamListener listener); + + /** + * shutdown internal stream consuming thread + * + * @since Twitter4J 2.1.7 + */ + void cleanUp(); + + /** + * Start consuming public statuses that match one or more filter predicates. + * At least one predicate parameter, follow, locations, or track must be + * specified. Multiple parameters may be specified which allows most clients + * to use a single connection to the Streaming API. Placing long parameters + * in the URL may cause the request to be rejected for excessive URL length.
+ * The default access level allows up to 200 track keywords, 400 follow + * userids and 10 1-degree location boxes. Increased access levels allow + * 80,000 follow userids ("shadow" role), 400,000 follow userids ("birddog" + * role), 10,000 track keywords ("restricted track" role), 200,000 track + * keywords ("partner track" role), and 200 10-degree location boxes + * ("locRestricted" role). Increased track access levels also pass a higher + * proportion of statuses before limiting the stream. + * + * @param query Filter query + * @see StatusStream + * @see Streaming + * API Methods statuses/filter + * @since Twitter4J 2.1.2 + */ + void filter(final FilterQuery query); + + /** + * Starts listening on all public statuses. Available only to approved + * parties and requires a signed agreement to access. Please do not contact + * us about access to the firehose. If your service warrants access to it, + * we'll contact you. + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @see StatusStream + * @see Streaming + * API Methods statuses/firehose + * @since Twitter4J 2.0.4 + */ + void firehose(final int count); + + /** + * Returns public statuses that match one or more filter predicates. At + * least one predicate parameter, follow, locations, or track must be + * specified. Multiple parameters may be specified which allows most clients + * to use a single connection to the Streaming API. Placing long parameters + * in the URL may cause the request to be rejected for excessive URL length.
+ * The default access level allows up to 200 track keywords, 400 follow + * userids and 10 1-degree location boxes. Increased access levels allow + * 80,000 follow userids ("shadow" role), 400,000 follow userids ("birddog" + * role), 10,000 track keywords ("restricted track" role), 200,000 track + * keywords ("partner track" role), and 200 10-degree location boxes + * ("locRestricted" role). Increased track access levels also pass a higher + * proportion of statuses before limiting the stream. + * + * @param query Filter query + * @return StatusStream + * @throws TwitterException when Twitter service or network is unavailable + * @see StatusStream + * @see Streaming + * API Methods | Twitter Developers + * @since Twitter4J 2.1.2 + * @deprecated use {@link #filter(twitter4j.FilterQuery)} instead + */ + @Deprecated + StatusStream getFilterStream(FilterQuery query) throws TwitterException; + + /** + * Returns a status stream of all public statuses. Available only to + * approved parties and requires a signed agreement to access. Please do not + * contact us about access to the firehose. If your service warrants access + * to it, we'll contact you. + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @return StatusStream + * @throws TwitterException when Twitter service or network is unavailable + * @see StatusStream + * @see Streaming + * API Methods statuses/firehose + * @since Twitter4J 2.0.4 + * @deprecated use {@link #firehose(int)} instead + */ + @Deprecated + StatusStream getFirehoseStream(int count) throws TwitterException; + + /** + * Returns a status stream of all public statuses containing links. + * Available only to approved parties and requires a signed agreement to + * access. Please do not contact us about access to the links stream. If + * your service warrants access to it, we'll contact you. + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @return StatusStream + * @throws TwitterException when Twitter service or network is unavailable + * @see StatusStream + * @see Streaming + * API Methods statuses/links + * @since Twitter4J 2.1.1 + * @deprecated use {@link #links(int)} instead + */ + @Deprecated + StatusStream getLinksStream(int count) throws TwitterException; + + /** + * Returns a stream of all retweets. The retweet stream is not a generally + * available resource. Few applications require this level of access. + * Creative use of a combination of other resources and various access + * levels can satisfy nearly every application use case. As of 9/11/2009, + * the site-wide retweet feature has not yet launched, so there are + * currently few, if any, retweets on this stream. + * + * @return StatusStream + * @throws TwitterException when Twitter service or network is unavailable + * @see StatusStream + * @see Streaming + * API: Methods statuses/retweet + * @since Twitter4J 2.0.10 + * @deprecated use {@link #getRetweetStream()} instead + */ + @Deprecated + StatusStream getRetweetStream() throws TwitterException; + + /** + * Returns a stream of random sample of all public statuses. The default + * access level provides a small proportion of the Firehose. The + * "Gardenhose" access level provides a proportion more suitable for data + * mining and research applications that desire a larger proportion to be + * statistically significant sample. + * + * @return StatusStream + * @throws TwitterException when Twitter service or network is unavailable + * @see StatusStream + * @see Streaming + * API: Methods statuses/sample + * @since Twitter4J 2.0.10 + * @deprecated use {@link #sample()} instead + */ + @Deprecated + StatusStream getSampleStream() throws TwitterException; + + /** + * User Streams provides real-time updates of all data needed to update a + * desktop application display. Applications can request startup back-fill + * from the REST API and then transition to Streaming for nearly all + * subsequent reads. Rate limits and latency are practically eliminated. + * Desktop developers can stop managing rate limits and use this new data to + * create an entirely new user experience. On our end, we hope to reduce + * costs and increase site reliability. + * + * @return UserStream + * @throws TwitterException when Twitter service or network is unavailable + * @see User + * Streams + * @deprecated use {@link #user()} instead + */ + @Deprecated + UserStream getUserStream() throws TwitterException; + + /** + * User Streams provides real-time updates of all data needed to update a + * desktop application display. Applications can request startup back-fill + * from the REST API and then transition to Streaming for nearly all + * subsequent reads. Rate limits and latency are practically eliminated. + * Desktop developers can stop managing rate limits and use this new data to + * create an entirely new user experience. On our end, we hope to reduce + * costs and increase site reliability. + * + * @param track keywords to track + * @return UserStream + * @throws TwitterException when Twitter service or network is unavailable + * @see User + * Streams + * @since Twitter4J 2.1.9 + * @deprecated use {@link #user()} instead + */ + @Deprecated + UserStream getUserStream(String[] track) throws TwitterException; + + /** + * Starts listening on all public statuses containing links. Available only + * to approved parties and requires a signed agreement to access. Please do + * not contact us about access to the links stream. If your service warrants + * access to it, we'll contact you. + * + * @param count Indicates the number of previous statuses to stream before + * transitioning to the live stream. + * @see StatusStream + * @see Streaming + * API Methods statuses/links + * @since Twitter4J 2.1.1 + */ + void links(final int count); + + /** + * Starts listening on all retweets. The retweet stream is not a generally + * available resource. Few applications require this level of access. + * Creative use of a combination of other resources and various access + * levels can satisfy nearly every application use case. As of 9/11/2009, + * the site-wide retweet feature has not yet launched, so there are + * currently few, if any, retweets on this stream. + * + * @see StatusStream + * @see Streaming + * API Methods statuses/retweet + * @since Twitter4J 2.0.10 + */ + void retweet(); + + /** + * Starts listening on random sample of all public statuses. The default + * access level provides a small proportion of the Firehose. The + * "Gardenhose" access level provides a proportion more suitable for data + * mining and research applications that desire a larger proportion to be + * statistically significant sample. + * + * @see StatusStream + * @see Streaming + * API: Methods statuses/sample + * @since Twitter4J 2.0.10 + */ + void sample(); + + /** + * Shuts down internal dispatcher thread shared by all TwitterStream + * instances.
+ * + * @since Twitter4J 2.1.9 + */ + @Override + void shutdown(); + + /** + * Site Streams, a new feature on the Streaming API, is now available for + * beta testing. Site Streams allows services, such as web sites or mobile + * push services, to receive real-time updates for a large number of users + * without any of the hassles of managing REST API rate limits. The initial + * version delivers events created by, or directed to, users that have + * shared their OAuth token with your application. The following events are + * streamed immediately, and without rate limits: Home Timelines, Mentions + * Timelines, User Timelines, Direct Messages, Mentions, Follows, Favorites, + * Tweets, Retweets, Profile changes, and List changes. The following + * limitations must be respected during the beta period. These limitations + * may be changed with little advance notice. We intend to increase or + * remove these various limitations as we move from beta test into full + * production:
+ * Limit the follow count to 100 users per stream. Clients must occasionally + * compact users onto a smaller number of connections to minimize the total + * number of connections outstanding.
+ * Open no more than 25 new connections per second and exponentially + * back-off on errors. + * + * @param withFollowings whether to receive status updates from people + * following + * @param follow an array of users to include in the stream + * @see Site + * Streams | Twitter Developers + * @since Twitter4J 2.1.8 + */ + StreamController site(final boolean withFollowings, final long[] follow); + + /** + * User Streams provides real-time updates of all data needed to update a + * desktop application display. Applications can request startup back-fill + * from the REST API and then transition to Streaming for nearly all + * subsequent reads. Rate limits and latency are practically eliminated. + * Desktop developers can stop managing rate limits and use this new data to + * create an entirely new user experience. On our end, we hope to reduce + * costs and increase site reliability. + * + * @throws IllegalStateException when non-UserStreamListener is set, or no + * listener is set + * @see User + * Streams + */ + void user(); + + /** + * User Streams provides real-time updates of all data needed to update a + * desktop application display. Applications can request startup back-fill + * from the REST API and then transition to Streaming for nearly all + * subsequent reads. Rate limits and latency are practically eliminated. + * Desktop developers can stop managing rate limits and use this new data to + * create an entirely new user experience. On our end, we hope to reduce + * costs and increase site reliability. + * + * @param track keywords to track + * @throws IllegalStateException when non-UserStreamListener is set, or no + * listener is set + * @see User + * Streams + * @since Twitter4J 2.1.9 + */ + void user(final String[] track); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamConstants.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamConstants.java new file mode 100644 index 00000000..7b7be44f --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamConstants.java @@ -0,0 +1,7 @@ +package twitter4j; + +public interface TwitterStreamConstants extends TwitterConstants { + public static final String DEFAULT_STREAM_BASE_URL = "https://stream.twitter.com/1.1/"; + public static final String DEFAULT_USER_STREAM_BASE_URL = "https://userstream.twitter.com/1.1/"; + public static final String DEFAULT_SITE_STREAM_BASE_URL = "https://sitestream.twitter.com/1.1/"; +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamFactory.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamFactory.java new file mode 100644 index 00000000..783ee827 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamFactory.java @@ -0,0 +1,120 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import twitter4j.auth.AccessToken; +import twitter4j.auth.Authorization; +import twitter4j.auth.AuthorizationFactory; +import twitter4j.auth.OAuthAuthorization; +import twitter4j.conf.StreamConfiguration; +import twitter4j.conf.StreamConfigurationContext; + +/** + * A factory class for TwitterFactory.
+ * An instance of this class is completely thread safe and can be re-used and + * used concurrently.
+ * Note that TwitterStream is NOT compatible with Google App Engine as GAE is + * not capable of handling requests longer than 30 seconds. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.0 + */ +public final class TwitterStreamFactory implements java.io.Serializable { + private static final long serialVersionUID = 8146074704915782233L; + private final StreamConfiguration conf; + private static final TwitterStream SINGLETON; + + static { + SINGLETON = new TwitterStreamImpl(StreamConfigurationContext.getInstance(), + TwitterFactory.DEFAULT_AUTHORIZATION); + } + + /** + * Creates a TwitterStreamFactory with the root configuration. + */ + public TwitterStreamFactory() { + this(StreamConfigurationContext.getInstance()); + } + + /** + * Creates a TwitterStreamFactory with the given configuration. + * + * @param conf the configuration to use + * @since Twitter4J 2.1.1 + */ + public TwitterStreamFactory(final StreamConfiguration conf) { + this.conf = conf; + } + + // implementations for BasicSupportFactory + + /** + * Returns a instance associated with the configuration bound to this + * factory. + * + * @return default instance + */ + public TwitterStream getInstance() { + return getInstance(AuthorizationFactory.getInstance(conf)); + } + + /** + * Returns a OAuth Authenticated instance.
+ * consumer key and consumer Secret must be provided by + * twitter4j.properties, or system properties. Unlike + * {@link twitter4j.TwitterStream#setOAuthAccessToken(twitter4j.auth.AccessToken)}, + * this factory method potentially returns a cached instance. + * + * @param accessToken access token + * @return an instance + */ + public TwitterStream getInstance(final AccessToken accessToken) { + final String consumerKey = conf.getOAuthConsumerKey(); + final String consumerSecret = conf.getOAuthConsumerSecret(); + if (null == consumerKey && null == consumerSecret) + throw new IllegalStateException("Consumer key and Consumer secret not supplied."); + final OAuthAuthorization oauth = new OAuthAuthorization(conf); + oauth.setOAuthAccessToken(accessToken); + return getInstance(conf, oauth); + } + + /** + * Returns a instance. + * + * @return an instance + */ + public TwitterStream getInstance(final Authorization auth) { + return getInstance(conf, auth); + } + + private TwitterStream getInstance(final StreamConfiguration conf, final Authorization auth) { + return new TwitterStreamImpl(conf, auth); + } + + /** + * Returns default singleton TwitterStream instance. + * + * @return default singleton TwitterStream instance + * @since Twitter4J 2.2.4 + */ + public static TwitterStream getSingleton() { + return SINGLETON; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamImpl.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamImpl.java new file mode 100755 index 00000000..9811c47b --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/TwitterStreamImpl.java @@ -0,0 +1,671 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package twitter4j; + +import static twitter4j.http.HttpResponseCode.FORBIDDEN; +import static twitter4j.http.HttpResponseCode.NOT_ACCEPTABLE; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import twitter4j.auth.Authorization; +import twitter4j.conf.StreamConfiguration; +import twitter4j.http.HttpParameter; +import twitter4j.internal.async.Dispatcher; +import twitter4j.internal.async.DispatcherFactory; +import twitter4j.internal.logging.Logger; +import twitter4j.internal.util.InternalStringUtil; + +/** + * A java representation of the Streaming API: + * Methods
+ * Note that this class is NOT compatible with Google App Engine as GAE is not + * capable of handling requests longer than 30 seconds. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.4 + */ +class TwitterStreamImpl extends TwitterBaseImpl implements TwitterStream { + private final StreamConfiguration conf; + private static final Logger logger = Logger.getLogger(TwitterStreamImpl.class); + + private final List lifeCycleListeners = new ArrayList(0); + private TwitterStreamConsumer handler = null; + + private final HttpParameter STALL_WARNINGS; + + private static transient Dispatcher dispatcher; + + /* Streaming API */ + + private static int numberOfHandlers = 0; + + private final List userStreamListeners = new ArrayList(0); + + private final List statusListeners = new ArrayList(0); + + private final List siteStreamsListeners = new ArrayList(0); + + private final List rawStreamListeners = new ArrayList(0); + + /* + * https://dev.twitter.com/docs/streaming-api/concepts#connecting When a + * network error (TCP/IP level) is encountered, back off linearly. Perhaps + * start at 250 milliseconds, double, and cap at 16 seconds When a HTTP + * error (> 200) is returned, back off exponentially. Perhaps start with a + * 10 second wait, double on each subsequent failure, and finally cap the + * wait at 240 seconds. Consider sending an alert to a human operator after + * multiple HTTP errors, as there is probably a client configuration issue + * that is unlikely to be resolved without human intervention. There's not + * much point in polling any faster in the face of HTTP error codes and your + * client is may run afoul of a rate limit. + */ + private static final int TCP_ERROR_INITIAL_WAIT = 250; + + private static final int TCP_ERROR_WAIT_CAP = 16 * 1000; + + private static final int HTTP_ERROR_INITIAL_WAIT = 10 * 1000; + + private static final int HTTP_ERROR_WAIT_CAP = 240 * 1000; + + private static final int NO_WAIT = 0; + + static int count = 0; + + /* package */ + TwitterStreamImpl(final StreamConfiguration conf, final Authorization auth) { + super(conf, auth); + this.conf = conf; + STALL_WARNINGS = new HttpParameter("stall_warnings", conf.isStallWarningsEnabled()); + } + + /** + * {@inheritDoc} + */ + @Override + public void addConnectionLifeCycleListener(final ConnectionLifeCycleListener listener) { + lifeCycleListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + @Override + public void addListener(final RawStreamListener listener) { + rawStreamListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + @Override + public void addListener(final SiteStreamsListener listener) { + siteStreamsListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + @Override + public void addListener(final StatusListener listener) { + statusListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + @Override + public void addListener(final UserStreamListener listener) { + statusListeners.add(listener); + userStreamListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void cleanUp() { + if (handler != null) { + handler.close(); + numberOfHandlers--; + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + final TwitterStreamImpl that = (TwitterStreamImpl) o; + + if (handler != null ? !handler.equals(that.handler) : that.handler != null) return false; + if (http != null ? !http.equals(that.http) : that.http != null) return false; + if (lifeCycleListeners != null ? !lifeCycleListeners.equals(that.lifeCycleListeners) + : that.lifeCycleListeners != null) return false; + if (rawStreamListeners != null ? !rawStreamListeners.equals(that.rawStreamListeners) + : that.rawStreamListeners != null) return false; + if (siteStreamsListeners != null ? !siteStreamsListeners.equals(that.siteStreamsListeners) + : that.siteStreamsListeners != null) return false; + if (STALL_WARNINGS != null ? !STALL_WARNINGS.equals(that.STALL_WARNINGS) : that.STALL_WARNINGS != null) + return false; + if (statusListeners != null ? !statusListeners.equals(that.statusListeners) : that.statusListeners != null) + return false; + if (userStreamListeners != null ? !userStreamListeners.equals(that.userStreamListeners) + : that.userStreamListeners != null) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void filter(final FilterQuery query) { + ensureAuthorizationEnabled(); + ensureStatusStreamListenerIsSet(); + startHandler(new TwitterStreamConsumer(statusListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + return getFilterStream(query); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + public void firehose(final int count) { + ensureAuthorizationEnabled(); + ensureStatusStreamListenerIsSet(); + startHandler(new TwitterStreamConsumer(statusListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + return getFirehoseStream(count); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + public StatusStream getFilterStream(final FilterQuery query) throws TwitterException { + ensureAuthorizationEnabled(); + try { + return new StatusStreamImpl(getDispatcher(), + http.post(conf.getStreamBaseURL() + "statuses/filter.json", conf.getStreamBaseURL() + + "statuses/filter.json", query.asHttpParameterArray(STALL_WARNINGS), auth), conf); + } catch (final IOException e) { + throw new TwitterException(e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public StatusStream getFirehoseStream(final int count) throws TwitterException { + ensureAuthorizationEnabled(); + return getCountStream("statuses/firehose.json", count); + } + + /** + * {@inheritDoc} + */ + @Override + public StatusStream getLinksStream(final int count) throws TwitterException { + ensureAuthorizationEnabled(); + return getCountStream("statuses/links.json", count); + } + + /** + * {@inheritDoc} + */ + @Override + public StatusStream getRetweetStream() throws TwitterException { + ensureAuthorizationEnabled(); + try { + return new StatusStreamImpl(getDispatcher(), http.post(conf.getStreamBaseURL() + "statuses/retweet.json", + conf.getStreamBaseURL() + "statuses/retweet.json", new HttpParameter[] { STALL_WARNINGS }, auth), + conf); + } catch (final IOException e) { + throw new TwitterException(e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public StatusStream getSampleStream() throws TwitterException { + ensureAuthorizationEnabled(); + try { + return new StatusStreamImpl(getDispatcher(), get(conf.getStreamBaseURL() + "statuses/sample.json", + conf.getStreamBaseURL() + "statuses/sample.json", STALL_WARNINGS), conf); + } catch (final IOException e) { + throw new TwitterException(e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserStream getUserStream() throws TwitterException { + return getUserStream(null); + } + + /** + * {@inheritDoc} + */ + @Override + public UserStream getUserStream(final String[] track) throws TwitterException { + ensureAuthorizationEnabled(); + try { + final List params = new ArrayList(); + params.add(STALL_WARNINGS); + if (conf.isUserStreamRepliesAllEnabled()) { + params.add(new HttpParameter("replies", "all")); + } + if (track != null) { + params.add(new HttpParameter("track", InternalStringUtil.join(track))); + } + return new UserStreamImpl(getDispatcher(), http.post(conf.getUserStreamBaseURL() + "user.json", + conf.getUserStreamBaseURL() + "user.json", params.toArray(new HttpParameter[params.size()]), auth), + conf); + } catch (final IOException e) { + throw new TwitterException(e); + } + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (http != null ? http.hashCode() : 0); + result = 31 * result + (lifeCycleListeners != null ? lifeCycleListeners.hashCode() : 0); + result = 31 * result + (handler != null ? handler.hashCode() : 0); + result = 31 * result + (STALL_WARNINGS != null ? STALL_WARNINGS.hashCode() : 0); + result = 31 * result + (userStreamListeners != null ? userStreamListeners.hashCode() : 0); + result = 31 * result + (statusListeners != null ? statusListeners.hashCode() : 0); + result = 31 * result + (siteStreamsListeners != null ? siteStreamsListeners.hashCode() : 0); + result = 31 * result + (rawStreamListeners != null ? rawStreamListeners.hashCode() : 0); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public void links(final int count) { + ensureAuthorizationEnabled(); + ensureStatusStreamListenerIsSet(); + startHandler(new TwitterStreamConsumer(statusListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + return getLinksStream(count); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + public void retweet() { + ensureAuthorizationEnabled(); + ensureStatusStreamListenerIsSet(); + startHandler(new TwitterStreamConsumer(statusListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + return getRetweetStream(); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + public void sample() { + ensureAuthorizationEnabled(); + ensureStatusStreamListenerIsSet(); + startHandler(new TwitterStreamConsumer(statusListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + return getSampleStream(); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void shutdown() { + super.shutdown(); + cleanUp(); + synchronized (TwitterStreamImpl.class) { + if (0 == numberOfHandlers) { + if (dispatcher != null) { + dispatcher.shutdown(); + dispatcher = null; + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public StreamController site(final boolean withFollowings, final long[] follow) { + ensureOAuthEnabled(); + ensureSiteStreamsListenerIsSet(); + final StreamController cs = new StreamController(http, auth); + startHandler(new TwitterStreamConsumer(siteStreamsListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + try { + return new SiteStreamsImpl(getDispatcher(), getSiteStream(withFollowings, follow), conf, cs); + } catch (final IOException e) { + throw new TwitterException(e); + } + } + }); + return cs; + } + + @Override + public String toString() { + return "TwitterStreamImpl{http=" + http + ", conf=" + conf + ", lifeCycleListeners=" + lifeCycleListeners + + ", handler=" + handler + ", STALL_WARNINGS=" + STALL_WARNINGS + ", userStreamListeners=" + + userStreamListeners + ", statusListeners=" + statusListeners + ", siteStreamsListeners=" + + siteStreamsListeners + ", rawStreamListeners=" + rawStreamListeners + "}"; + } + + /** + * {@inheritDoc} + */ + @Override + public void user() { + user(null); + } + + /** + * {@inheritDoc} + */ + @Override + public void user(final String[] track) { + ensureAuthorizationEnabled(); + ensureUserStreamListenerIsSet(); + startHandler(new TwitterStreamConsumer(statusListeners, rawStreamListeners) { + @Override + public StatusStream getStream() throws TwitterException { + return getUserStream(track); + } + }); + } + + private void ensureSiteStreamsListenerIsSet() { + if (siteStreamsListeners.size() == 0 && rawStreamListeners.size() == 0) + throw new IllegalStateException("SiteStreamsListener is not set."); + } + + /** + * check if any listener is set. Throws IllegalStateException if no listener + * is set. + * + * @throws IllegalStateException when no listener is set. + */ + + private void ensureStatusStreamListenerIsSet() { + if (statusListeners.size() == 0 && rawStreamListeners.size() == 0) + throw new IllegalStateException("StatusListener is not set."); + } + + private void ensureUserStreamListenerIsSet() { + if (userStreamListeners.size() == 0 && rawStreamListeners.size() == 0) + throw new IllegalStateException("UserStreamListener is not set."); + } + + private StatusStream getCountStream(final String relativeUrl, final int count) throws TwitterException { + ensureAuthorizationEnabled(); + try { + return new StatusStreamImpl(getDispatcher(), http.post(conf.getStreamBaseURL() + relativeUrl, + conf.getStreamBaseURL() + relativeUrl, + new HttpParameter[] { new HttpParameter("count", String.valueOf(count)), STALL_WARNINGS }, auth), + conf); + } catch (final IOException e) { + throw new TwitterException(e); + } + } + + private Dispatcher getDispatcher() { + if (null == TwitterStreamImpl.dispatcher) { + synchronized (TwitterStreamImpl.class) { + if (null == TwitterStreamImpl.dispatcher) { + // dispatcher is held statically, but it'll be instantiated + // with + // the configuration instance associated with this + // TwitterStream + // instance which invokes getDispatcher() on the first time. + TwitterStreamImpl.dispatcher = new DispatcherFactory(conf).getInstance(); + } + } + } + return TwitterStreamImpl.dispatcher; + } + + private synchronized void startHandler(final TwitterStreamConsumer handler) { + cleanUp(); + this.handler = handler; + this.handler.start(); + numberOfHandlers++; + } + + InputStream getSiteStream(final boolean withFollowings, final long[] follow) throws TwitterException { + ensureOAuthEnabled(); + return http.post( + conf.getSiteStreamBaseURL() + "site.json", + conf.getSiteStreamBaseURL() + "site.json", + new HttpParameter[] { new HttpParameter("with", withFollowings ? "followings" : "user"), + new HttpParameter("follow", InternalStringUtil.join(follow)), STALL_WARNINGS }, auth) + .asStream(); + } + + abstract class TwitterStreamConsumer extends Thread { + private StatusStreamBase stream = null; + private final String NAME = "Twitter Stream consumer-" + ++count; + private volatile boolean closed = false; + private final StreamListener[] streamListeners; + private final RawStreamListener[] rawStreamListeners; + + TwitterStreamConsumer(final List streamListeners, + final List rawStreamListeners) { + super(); + setName(NAME + "[initializing]"); + this.streamListeners = streamListeners.toArray(new StreamListener[streamListeners.size()]); + this.rawStreamListeners = rawStreamListeners.toArray(new RawStreamListener[rawStreamListeners.size()]); + } + + public synchronized void close() { + setStatus("[Disposing thread]"); + try { + if (stream != null) { + try { + stream.close(); + } catch (final IOException ignore) { + } catch (final Exception e) { + e.printStackTrace(); + logger.warn(e.getMessage()); + } + } + } finally { + closed = true; + } + } + + @Override + public void run() { + int timeToSleep = NO_WAIT; + boolean connected = false; + while (!closed) { + try { + if (!closed && null == stream) { + // try establishing connection + logger.info("Establishing connection."); + setStatus("[Establishing connection]"); + stream = (StatusStreamBase) getStream(); + connected = true; + logger.info("Connection established."); + for (final ConnectionLifeCycleListener listener : lifeCycleListeners) { + try { + listener.onConnect(); + } catch (final Exception e) { + logger.warn(e.getMessage()); + } + } + // connection established successfully + timeToSleep = NO_WAIT; + logger.info("Receiving status stream."); + setStatus("[Receiving stream]"); + while (!closed) { + try { + stream.next(streamListeners, rawStreamListeners); + } catch (final IllegalStateException ise) { + logger.warn(ise.getMessage()); + break; + } catch (final TwitterException e) { + logger.info(e.getMessage()); + stream.onException(e, streamListeners, rawStreamListeners); + throw e; + } catch (final Exception e) { + logger.info(e.getMessage()); + stream.onException(e, streamListeners, rawStreamListeners); + closed = true; + break; + } + } + } + } catch (final TwitterException te) { + logger.info(te.getMessage()); + if (!closed) { + if (NO_WAIT == timeToSleep) { + if (te.getStatusCode() == FORBIDDEN) { + logger.warn("This account is not in required role. ", te.getMessage()); + closed = true; + for (final StreamListener statusListener : streamListeners) { + statusListener.onException(te); + } + break; + } + if (te.getStatusCode() == NOT_ACCEPTABLE) { + logger.warn("Parameter not accepted with the role. ", te.getMessage()); + closed = true; + for (final StreamListener statusListener : streamListeners) { + statusListener.onException(te); + } + break; + } + connected = false; + for (final ConnectionLifeCycleListener listener : lifeCycleListeners) { + try { + listener.onDisconnect(); + } catch (final Exception e) { + logger.warn(e.getMessage()); + } + } + if (te.getStatusCode() > 200) { + timeToSleep = HTTP_ERROR_INITIAL_WAIT; + } else if (0 == timeToSleep) { + timeToSleep = TCP_ERROR_INITIAL_WAIT; + } + } + if (te.getStatusCode() > 200 && timeToSleep < HTTP_ERROR_INITIAL_WAIT) { + timeToSleep = HTTP_ERROR_INITIAL_WAIT; + } + if (connected) { + for (final ConnectionLifeCycleListener listener : lifeCycleListeners) { + try { + listener.onDisconnect(); + } catch (final Exception e) { + logger.warn(e.getMessage()); + } + } + } + for (final StreamListener statusListener : streamListeners) { + statusListener.onException(te); + } + // there was a problem establishing the connection, or + // the connection closed by peer + if (!closed) { + // wait for a moment not to overload Twitter API + logger.info("Waiting for " + timeToSleep + " milliseconds"); + setStatus("[Waiting for " + timeToSleep + " milliseconds]"); + try { + Thread.sleep(timeToSleep); + } catch (final InterruptedException ignore) { + } + timeToSleep = Math.min(timeToSleep * 2, te.getStatusCode() > 200 ? HTTP_ERROR_WAIT_CAP + : TCP_ERROR_WAIT_CAP); + } + stream = null; + logger.debug(te.getMessage()); + connected = false; + } + } + } + if (stream != null && connected) { + try { + stream.close(); + } catch (final IOException ignore) { + } catch (final Exception e) { + e.printStackTrace(); + logger.warn(e.getMessage()); + } finally { + for (final ConnectionLifeCycleListener listener : lifeCycleListeners) { + try { + listener.onDisconnect(); + } catch (final Exception e) { + logger.warn(e.getMessage()); + } + } + } + } + for (final ConnectionLifeCycleListener listener : lifeCycleListeners) { + try { + listener.onCleanUp(); + } catch (final Exception e) { + logger.warn(e.getMessage()); + } + } + } + + private void setStatus(final String message) { + final String actualMessage = NAME + message; + setName(actualMessage); + logger.debug(actualMessage); + } + + abstract StatusStream getStream() throws TwitterException; + + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStream.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStream.java new file mode 100644 index 00000000..1ab09c20 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStream.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.IOException; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +public interface UserStream extends StatusStream { + @Override + void close() throws IOException; + + /** + * Reads next element from this stream. + * + * @param listener a UserStreamListener implementation + * @throws TwitterException when the end of the stream has been reached. + * @throws IllegalStateException when the end of the stream had been + * reached. + */ + void next(UserStreamListener listener) throws TwitterException; +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamAdapter.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamAdapter.java new file mode 100644 index 00000000..8cf32fc4 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamAdapter.java @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +public class UserStreamAdapter extends StatusAdapter implements UserStreamListener { + @Override + public void onBlock(final User source, final User blockedUser) { + } + + @Override + public void onDeletionNotice(final long directMessageId, final long userId) { + } + + @Override + public void onDirectMessage(final DirectMessage directMessage) { + } + + @Override + public void onException(final Exception ex) { + } + + @Override + public void onFavorite(final User source, final User target, final Status favoritedStatus) { + } + + @Override + public void onFollow(final User source, final User followedUser) { + } + + @Override + public void onFriendList(final long[] friendIds) { + } + + @Override + public void onUnblock(final User source, final User unblockedUser) { + } + + @Override + public void onUnfavorite(final User source, final User target, final Status unfavoritedStatus) { + } + + @Override + public void onUserListCreation(final User listOwner, final UserList list) { + } + + @Override + public void onUserListDeletion(final User listOwner, final UserList list) { + } + + @Override + public void onUserListMemberAddition(final User addedMember, final User listOwner, final UserList list) { + } + + @Override + public void onUserListMemberDeletion(final User deletedMember, final User listOwner, final UserList list) { + } + + @Override + public void onUserListSubscription(final User subscriber, final User listOwner, final UserList list) { + } + + @Override + public void onUserListUnsubscription(final User subscriber, final User listOwner, final UserList list) { + } + + @Override + public void onUserListUpdate(final User listOwner, final UserList list) { + } + + @Override + public void onUserProfileUpdate(final User updatedUser) { + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamImpl.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamImpl.java new file mode 100644 index 00000000..715e1183 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamImpl.java @@ -0,0 +1,186 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.IOException; +import java.io.InputStream; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.conf.StreamConfiguration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.async.Dispatcher; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.8 + */ +class UserStreamImpl extends StatusStreamImpl implements UserStream { + /* package */UserStreamImpl(final Dispatcher dispatcher, final HttpResponse response, final StreamConfiguration conf) + throws IOException { + super(dispatcher, response, conf); + } + + /* package */UserStreamImpl(final Dispatcher dispatcher, final InputStream stream, final StreamConfiguration conf) + throws IOException { + super(dispatcher, stream, conf); + } + + @Override + public void next(final UserStreamListener listener) throws TwitterException { + handleNextElement(new StreamListener[] { listener }, EMPTY); + } + + @Override + protected void onBlock(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onBlock(asUser(source), asUser(target)); + } + } + + @Override + protected void onDirectMessage(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + final DirectMessage directMessage = asDirectMessage(json); + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onDirectMessage(directMessage); + } + } + + @Override + protected void onFavorite(final JSONObject source, final JSONObject target, final JSONObject targetObject, + final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onFavorite(asUser(source), asUser(target), asStatus(targetObject)); + } + } + + @Override + protected void onFollow(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onFollow(asUser(source), asUser(target)); + } + } + + @Override + protected void onFriends(final JSONObject json, final StreamListener[] listeners) throws TwitterException, + JSONException { + final long[] friendIds = asFriendList(json); + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onFriendList(friendIds); + } + } + + @Override + protected void onScrubGeo(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + // Not implemented yet + logger.info("Geo-tagging deletion notice (not implemented yet): " + line); + } + + @Override + protected void onSender(final JSONObject json, final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onDirectMessage(factory.createDirectMessage(json)); + } + } + + @Override + protected void onUnblock(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUnblock(asUser(source), asUser(target)); + } + } + + @Override + protected void onUnfavorite(final JSONObject source, final JSONObject target, final JSONObject targetObject, + final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUnfavorite(asUser(source), asUser(target), asStatus(targetObject)); + } + } + + @Override + protected void onUserListCreation(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListCreation(asUser(source), asUserList(target)); + } + } + + @Override + protected void onUserListDestroyed(final JSONObject source, final JSONObject target, + final StreamListener[] listeners) throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListDeletion(asUser(source), asUserList(target)); + } + } + + @Override + protected void onUserListMemberAddition(final JSONObject addedMember, final JSONObject owner, + final JSONObject target, final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListMemberAddition(asUser(addedMember), asUser(owner), + asUserList(target)); + } + } + + @Override + protected void onUserListMemberDeletion(final JSONObject deletedMember, final JSONObject owner, + final JSONObject target, final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListMemberDeletion(asUser(deletedMember), asUser(owner), + asUserList(target)); + } + } + + @Override + protected void onUserListSubscription(final JSONObject source, final JSONObject owner, final JSONObject target, + final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListSubscription(asUser(source), asUser(owner), asUserList(target)); + } + } + + @Override + protected void onUserListUnsubscription(final JSONObject source, final JSONObject owner, final JSONObject target, + final StreamListener[] listeners) throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListUnsubscription(asUser(source), asUser(owner), asUserList(target)); + } + } + + @Override + protected void onUserListUpdated(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException, JSONException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserListUpdate(asUser(source), asUserList(target)); + } + } + + @Override + protected void onUserUpdate(final JSONObject source, final JSONObject target, final StreamListener[] listeners) + throws TwitterException { + for (final StreamListener listener : listeners) { + ((UserStreamListener) listener).onUserProfileUpdate(asUser(source)); + } + } + +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamListener.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamListener.java new file mode 100644 index 00000000..b7bf4b7e --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/UserStreamListener.java @@ -0,0 +1,133 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +public interface UserStreamListener extends StatusListener { + /** + * @param source + * @param blockedUser + * @since Twitter4J 2.1.3 + */ + void onBlock(User source, User blockedUser); + + void onDeletionNotice(long directMessageId, long userId); + + /** + * @param directMessage + * @since Twitter4J 2.1.3 + */ + void onDirectMessage(DirectMessage directMessage); + + /** + * @param source + * @param target + * @param favoritedStatus + * @since Twitter4J 2.1.3 + */ + void onFavorite(User source, User target, Status favoritedStatus); + + /** + * @param source + * @param followedUser + * @since Twitter4J 2.1.3 + */ + void onFollow(User source, User followedUser); + + /** + * @param friendIds + * @since Twitter4J 2.1.3 + */ + void onFriendList(long[] friendIds); + + /** + * @param source + * @param unblockedUser + * @since Twitter4J 2.1.3 + */ + void onUnblock(User source, User unblockedUser); + + /** + * @param source + * @param target + * @param unfavoritedStatus + * @since Twitter4J 2.1.3 + */ + void onUnfavorite(User source, User target, Status unfavoritedStatus); + + /** + * @param listOwner + * @param list + * @since Twitter4J 2.1.3 + */ + void onUserListCreation(User listOwner, UserList list); + + /** + * @param listOwner + * @param list + * @since Twitter4J 2.1.3 + */ + void onUserListDeletion(User listOwner, UserList list); + + /** + * @param addedMember + * @param listOwner + * @param list + * @since Twitter4J 2.1.11 + */ + void onUserListMemberAddition(User addedMember, User listOwner, UserList list); + + /** + * @param deletedMember + * @param listOwner + * @param list + * @since Twitter4J 2.1.11 + */ + void onUserListMemberDeletion(User deletedMember, User listOwner, UserList list); + + /** + * @param subscriber + * @param listOwner + * @param list + * @since Twitter4J 2.1.3 + */ + void onUserListSubscription(User subscriber, User listOwner, UserList list); + + /** + * @param subscriber + * @param listOwner + * @param list + * @since Twitter4J 2.1.11 + */ + void onUserListUnsubscription(User subscriber, User listOwner, UserList list); + + /** + * @param listOwner + * @param list + * @since Twitter4J 2.1.3 + */ + void onUserListUpdate(User listOwner, UserList list); + + /** + * @param updatedUser updated user + * @since Twitter4J 2.1.9 + */ + void onUserProfileUpdate(User updatedUser); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/VersionStream.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/VersionStream.java new file mode 100644 index 00000000..591324a8 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/VersionStream.java @@ -0,0 +1,42 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class VersionStream { + private static final String VERSION = "3.0.3"; + private static final String TITLE = "Twitter4J Streaming API support"; + + private VersionStream() { + throw new AssertionError(); + } + + public static String getVersion() { + return VERSION; + } + + /** + * prints the version string + * + * @param args will be just ignored. + */ + public static void main(final String[] args) { + System.out.println(TITLE + " " + VERSION); + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/BaseStreamConfigurationFactory.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/BaseStreamConfigurationFactory.java new file mode 100644 index 00000000..edfd5918 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/BaseStreamConfigurationFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +/** + * ConfigurationFactory implementation for ConfigurationBase. Currently + * getInstance calls concrete constructor each time. No caching at all. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +class BaseStreamConfigurationFactory implements StreamConfigurationFactory { + private static final StreamConfigurationBase ROOT_CONFIGURATION; + + static { + ROOT_CONFIGURATION = new StreamConfigurationBase(); + } + + /** + * {@inheritDoc} + */ + @Override + public void dispose() { + // nothing to do for property based configuration + } + + // It may be preferable to cache the config instance + + /** + * {@inheritDoc} + */ + @Override + public StreamConfiguration getInstance() { + return ROOT_CONFIGURATION; + } + +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfiguration.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfiguration.java new file mode 100644 index 00000000..1ba0da50 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfiguration.java @@ -0,0 +1,23 @@ +package twitter4j.conf; + +public interface StreamConfiguration extends Configuration { + + int getAsyncNumThreads(); + + String getDispatcherImpl(); + + int getHttpStreamingReadTimeout(); + + String getSiteStreamBaseURL(); + + String getStreamBaseURL(); + + String getUserStreamBaseURL(); + + boolean isJSONStoreEnabled(); + + boolean isStallWarningsEnabled(); + + boolean isUserStreamRepliesAllEnabled(); + +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationBase.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationBase.java new file mode 100644 index 00000000..d0e83a5e --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationBase.java @@ -0,0 +1,153 @@ +package twitter4j.conf; + +import twitter4j.TwitterStreamConstants; + +class StreamConfigurationBase extends ConfigurationBase implements StreamConfiguration, TwitterStreamConstants { + + private String dispatcherImpl; + private String siteStreamBaseURL; + private String userStreamBaseURL; + private String streamBaseURL; + + private int httpStreamingReadTimeout; + private int asyncNumThreads; + + private boolean userStreamRepliesAllEnabled; + private boolean jsonStoreEnabled; + private boolean stallWarningsEnabled; + + protected StreamConfigurationBase() { + super(); + setAsyncNumThreads(1); + setHttpStreamingReadTimeout(40 * 1000); + setDispatcherImpl("twitter4j.internal.async.DispatcherImpl"); + setStreamBaseURL(DEFAULT_STREAM_BASE_URL); + setUserStreamBaseURL(DEFAULT_USER_STREAM_BASE_URL); + setSiteStreamBaseURL(DEFAULT_SITE_STREAM_BASE_URL); + setUserStreamRepliesAllEnabled(false); + } + + @Override + public final int getAsyncNumThreads() { + return asyncNumThreads; + } + + @Override + public String getDispatcherImpl() { + return dispatcherImpl; + } + + @Override + public int getHttpStreamingReadTimeout() { + return httpStreamingReadTimeout; + } + + @Override + public String getSiteStreamBaseURL() { + return siteStreamBaseURL; + } + + @Override + public String getStreamBaseURL() { + return streamBaseURL; + } + + @Override + public String getUserStreamBaseURL() { + return userStreamBaseURL; + } + + @Override + public boolean isJSONStoreEnabled() { + return jsonStoreEnabled; + } + + @Override + public boolean isStallWarningsEnabled() { + return stallWarningsEnabled; + } + + @Override + public boolean isUserStreamRepliesAllEnabled() { + return userStreamRepliesAllEnabled; + } + + public void setStallWarningsEnabled(final boolean isStallWarningsEnabled) { + stallWarningsEnabled = isStallWarningsEnabled; + } + + protected final void setAsyncNumThreads(final int asyncNumThreads) { + this.asyncNumThreads = asyncNumThreads; + } + + protected final void setDispatcherImpl(final String dispatcherImpl) { + this.dispatcherImpl = dispatcherImpl; + } + + protected final void setHttpStreamingReadTimeout(final int httpStreamingReadTimeout) { + this.httpStreamingReadTimeout = httpStreamingReadTimeout; + } + + protected final void setJSONStoreEnabled(final boolean enabled) { + jsonStoreEnabled = enabled; + } + + protected final void setSiteStreamBaseURL(String siteStreamBaseURL) { + if (isNullOrEmpty(siteStreamBaseURL)) { + siteStreamBaseURL = DEFAULT_SITE_STREAM_BASE_URL; + } + this.siteStreamBaseURL = fixURLSlash(siteStreamBaseURL); + fixSiteStreamBaseURL(); + } + + protected final void setStreamBaseURL(String streamBaseURL) { + if (isNullOrEmpty(streamBaseURL)) { + streamBaseURL = DEFAULT_STREAM_BASE_URL; + } + this.streamBaseURL = fixURLSlash(streamBaseURL); + fixStreamBaseURL(); + } + + protected final void setUserStreamBaseURL(String userStreamBaseURL) { + if (isNullOrEmpty(userStreamBaseURL)) { + userStreamBaseURL = DEFAULT_USER_STREAM_BASE_URL; + } + this.userStreamBaseURL = fixURLSlash(userStreamBaseURL); + fixUserStreamBaseURL(); + } + + protected final void setUserStreamRepliesAllEnabled(final boolean enabled) { + userStreamRepliesAllEnabled = enabled; + } + + private void fixSiteStreamBaseURL() { + if (DEFAULT_SITE_STREAM_BASE_URL.equals(fixURL(DEFAULT_USE_SSL, siteStreamBaseURL))) { + siteStreamBaseURL = fixURL(isSSLEnabled(), siteStreamBaseURL); + } + if (siteStreamBaseURL != null && siteStreamBaseURL.equals(fixURL(DEFAULT_USE_SSL, siteStreamBaseURL))) { + siteStreamBaseURL = fixURL(isSSLEnabled(), siteStreamBaseURL); + } + initRequestHeaders(); + } + + private void fixStreamBaseURL() { + if (DEFAULT_STREAM_BASE_URL.equals(fixURL(DEFAULT_USE_SSL, streamBaseURL))) { + streamBaseURL = fixURL(isSSLEnabled(), streamBaseURL); + } + if (streamBaseURL != null && streamBaseURL.equals(fixURL(DEFAULT_USE_SSL, streamBaseURL))) { + streamBaseURL = fixURL(isSSLEnabled(), streamBaseURL); + } + initRequestHeaders(); + } + + private void fixUserStreamBaseURL() { + if (DEFAULT_USER_STREAM_BASE_URL.equals(fixURL(DEFAULT_USE_SSL, userStreamBaseURL))) { + userStreamBaseURL = fixURL(isSSLEnabled(), userStreamBaseURL); + } + if (userStreamBaseURL != null && userStreamBaseURL.equals(fixURL(DEFAULT_USE_SSL, userStreamBaseURL))) { + userStreamBaseURL = fixURL(isSSLEnabled(), userStreamBaseURL); + } + initRequestHeaders(); + } + +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationBuilder.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationBuilder.java new file mode 100644 index 00000000..6d09f733 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationBuilder.java @@ -0,0 +1,297 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.conf; + +import twitter4j.http.HostAddressResolverFactory; +import twitter4j.http.HttpClientFactory; + +/** + * A builder that can be used to construct a twitter4j configuration with + * desired settings. This builder has sensible defaults such that + * {@code new ConfigurationBuilder().build()} would create a usable + * configuration. This configuration builder is useful for clients that wish to + * configure twitter4j in unit tests or from command line flags for example. + * + * @author John Sirois - john.sirois at gmail.com + */ +@SuppressWarnings("unused") +public final class StreamConfigurationBuilder { + + private StreamConfigurationBase configuration = new StreamConfigurationBase(); + + public StreamConfiguration build() { + checkNotBuilt(); + configuration.cacheInstance(); + try { + return configuration; + } finally { + configuration = null; + } + } + + public StreamConfigurationBuilder setAsyncNumThreads(final int asyncNumThreads) { + checkNotBuilt(); + configuration.setAsyncNumThreads(asyncNumThreads); + return this; + } + + public StreamConfigurationBuilder setClientName(final String clientName) { + checkNotBuilt(); + configuration.setClientName(clientName); + return this; + } + + public StreamConfigurationBuilder setClientURL(final String clientURL) { + checkNotBuilt(); + configuration.setClientURL(clientURL); + return this; + } + + public StreamConfigurationBuilder setClientVersion(final String clientVersion) { + checkNotBuilt(); + configuration.setClientVersion(clientVersion); + return this; + } + + public StreamConfigurationBuilder setDebugEnabled(final boolean debugEnabled) { + checkNotBuilt(); + configuration.setDebug(debugEnabled); + return this; + } + + public StreamConfigurationBuilder setDispatcherImpl(final String dispatcherImpl) { + checkNotBuilt(); + configuration.setDispatcherImpl(dispatcherImpl); + return this; + } + + public StreamConfigurationBuilder setGZIPEnabled(final boolean gzipEnabled) { + checkNotBuilt(); + configuration.setGZIPEnabled(gzipEnabled); + return this; + } + + public StreamConfigurationBuilder setHostAddressResolverFactory(final HostAddressResolverFactory factory) { + checkNotBuilt(); + configuration.setHostAddressResolverFactory(factory); + return this; + } + + public void setHttpClientFactory(HttpClientFactory factory) { + configuration.setHttpClientFactory(factory); + } + + public StreamConfigurationBuilder setHttpConnectionTimeout(final int httpConnectionTimeout) { + checkNotBuilt(); + configuration.setHttpConnectionTimeout(httpConnectionTimeout); + return this; + } + + public StreamConfigurationBuilder setHttpDefaultMaxPerRoute(final int httpDefaultMaxPerRoute) { + checkNotBuilt(); + configuration.setHttpDefaultMaxPerRoute(httpDefaultMaxPerRoute); + return this; + } + + public StreamConfigurationBuilder setHttpMaxTotalConnections(final int httpMaxConnections) { + checkNotBuilt(); + configuration.setHttpMaxTotalConnections(httpMaxConnections); + return this; + } + + public StreamConfigurationBuilder setHttpProxyHost(final String httpProxyHost) { + checkNotBuilt(); + configuration.setHttpProxyHost(httpProxyHost); + return this; + } + + public StreamConfigurationBuilder setHttpProxyPassword(final String httpProxyPassword) { + checkNotBuilt(); + configuration.setHttpProxyPassword(httpProxyPassword); + return this; + } + + public StreamConfigurationBuilder setHttpProxyPort(final int httpProxyPort) { + checkNotBuilt(); + configuration.setHttpProxyPort(httpProxyPort); + return this; + } + + public StreamConfigurationBuilder setHttpProxyUser(final String httpProxyUser) { + checkNotBuilt(); + configuration.setHttpProxyUser(httpProxyUser); + return this; + } + + public StreamConfigurationBuilder setHttpReadTimeout(final int httpReadTimeout) { + checkNotBuilt(); + configuration.setHttpReadTimeout(httpReadTimeout); + return this; + } + + public StreamConfigurationBuilder setHttpRetryCount(final int httpRetryCount) { + checkNotBuilt(); + configuration.setHttpRetryCount(httpRetryCount); + return this; + } + + public StreamConfigurationBuilder setHttpRetryIntervalSeconds(final int httpRetryIntervalSeconds) { + checkNotBuilt(); + configuration.setHttpRetryIntervalSeconds(httpRetryIntervalSeconds); + return this; + } + + public StreamConfigurationBuilder setHttpStreamingReadTimeout(final int httpStreamingReadTimeout) { + checkNotBuilt(); + configuration.setHttpStreamingReadTimeout(httpStreamingReadTimeout); + return this; + } + + public StreamConfigurationBuilder setIgnoreSSLError(final boolean ignoreSSLError) { + checkNotBuilt(); + configuration.setIgnoreSSLError(ignoreSSLError); + return this; + } + + public StreamConfigurationBuilder setIncludeEntitiesEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setIncludeEntitiesEnabled(enabled); + return this; + } + + public StreamConfigurationBuilder setIncludeRTsEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setIncludeRTsEnabled(enabled); + return this; + } + + public StreamConfigurationBuilder setJSONStoreEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setJSONStoreEnabled(enabled); + return this; + } + + public StreamConfigurationBuilder setOAuthAccessToken(final String oAuthAccessToken) { + checkNotBuilt(); + configuration.setOAuthAccessToken(oAuthAccessToken); + return this; + } + + public StreamConfigurationBuilder setOAuthAccessTokenSecret(final String oAuthAccessTokenSecret) { + checkNotBuilt(); + configuration.setOAuthAccessTokenSecret(oAuthAccessTokenSecret); + return this; + } + + public StreamConfigurationBuilder setOAuthBaseURL(final String oAuthBaseURL) { + checkNotBuilt(); + configuration.setOAuthBaseURL(oAuthBaseURL); + return this; + } + + public StreamConfigurationBuilder setOAuthConsumerKey(final String oAuthConsumerKey) { + checkNotBuilt(); + configuration.setOAuthConsumerKey(oAuthConsumerKey); + return this; + } + + public StreamConfigurationBuilder setOAuthConsumerSecret(final String oAuthConsumerSecret) { + checkNotBuilt(); + configuration.setOAuthConsumerSecret(oAuthConsumerSecret); + return this; + } + + public StreamConfigurationBuilder setPassword(final String password) { + checkNotBuilt(); + configuration.setPassword(password); + return this; + } + + public StreamConfigurationBuilder setPrettyDebugEnabled(final boolean prettyDebugEnabled) { + checkNotBuilt(); + configuration.setPrettyDebugEnabled(prettyDebugEnabled); + return this; + } + + public StreamConfigurationBuilder setRestBaseURL(final String restBaseURL) { + checkNotBuilt(); + configuration.setRestBaseURL(restBaseURL); + return this; + } + + public StreamConfigurationBuilder setSigningOAuthBaseURL(final String signingOAuthBaseURL) { + checkNotBuilt(); + configuration.setSigningOAuthBaseURL(signingOAuthBaseURL); + return this; + } + + public StreamConfigurationBuilder setSigningRestBaseURL(final String signingRestBaseURL) { + checkNotBuilt(); + configuration.setSigningRestBaseURL(signingRestBaseURL); + return this; + } + + public StreamConfigurationBuilder setSiteStreamBaseURL(final String siteStreamBaseURL) { + checkNotBuilt(); + configuration.setSiteStreamBaseURL(siteStreamBaseURL); + return this; + } + + public StreamConfigurationBuilder setStreamBaseURL(final String streamBaseURL) { + checkNotBuilt(); + configuration.setStreamBaseURL(streamBaseURL); + return this; + } + + public StreamConfigurationBuilder setUser(final String user) { + checkNotBuilt(); + configuration.setUser(user); + return this; + } + + public StreamConfigurationBuilder setHttpUserAgent(final String userAgent) { + checkNotBuilt(); + configuration.setHttpUserAgent(userAgent); + return this; + } + + public StreamConfigurationBuilder setUserStreamBaseURL(final String siteStreamBaseURL) { + checkNotBuilt(); + configuration.setUserStreamBaseURL(siteStreamBaseURL); + return this; + } + + public StreamConfigurationBuilder setUserStreamRepliesAllEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setUserStreamRepliesAllEnabled(enabled); + return this; + } + + public StreamConfigurationBuilder setUseSSL(final boolean useSSL) { + checkNotBuilt(); + configuration.setUseSSL(useSSL); + return this; + } + + private void checkNotBuilt() { + if (configuration == null) + throw new IllegalStateException("Cannot use this builder any longer, build() has already been called"); + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationContext.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationContext.java new file mode 100644 index 00000000..0a8cc61d --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationContext.java @@ -0,0 +1,9 @@ +package twitter4j.conf; + +public class StreamConfigurationContext { + private static final StreamConfigurationFactory factory = new BaseStreamConfigurationFactory(); + + public static StreamConfiguration getInstance() { + return factory.getInstance(); + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationFactory.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationFactory.java new file mode 100644 index 00000000..afa14abf --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/conf/StreamConfigurationFactory.java @@ -0,0 +1,12 @@ +package twitter4j.conf; + +public interface StreamConfigurationFactory extends ConfigurationFactory { + + /** + * returns the root configuration + * + * @return root configuration + */ + @Override + StreamConfiguration getInstance(); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/Dispatcher.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/Dispatcher.java new file mode 100644 index 00000000..4906b41a --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/Dispatcher.java @@ -0,0 +1,27 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.async; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface Dispatcher { + + void invokeLater(Runnable task); + + void shutdown(); +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/DispatcherFactory.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/DispatcherFactory.java new file mode 100644 index 00000000..9dc1da02 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/DispatcherFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.async; + +import java.lang.reflect.InvocationTargetException; + +import twitter4j.conf.StreamConfiguration; +import twitter4j.conf.StreamConfigurationContext; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +public final class DispatcherFactory { + private final String dispatcherImpl; + private final StreamConfiguration conf; + + public DispatcherFactory() { + this(StreamConfigurationContext.getInstance()); + } + + public DispatcherFactory(final StreamConfiguration conf) { + dispatcherImpl = conf.getDispatcherImpl(); + this.conf = conf; + } + + /** + * returns a Dispatcher instance. + * + * @return dispatcher instance + */ + public Dispatcher getInstance() { + try { + return (Dispatcher) Class.forName(dispatcherImpl).getConstructor(StreamConfiguration.class) + .newInstance(conf); + } catch (final InstantiationException e) { + throw new AssertionError(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final ClassNotFoundException e) { + throw new AssertionError(e); + } catch (final ClassCastException e) { + throw new AssertionError(e); + } catch (final NoSuchMethodException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new AssertionError(e); + } + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/DispatcherImpl.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/DispatcherImpl.java new file mode 100644 index 00000000..5d07abf3 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/async/DispatcherImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package twitter4j.internal.async; + +import java.util.LinkedList; +import java.util.List; + +import twitter4j.conf.StreamConfiguration; +import twitter4j.internal.logging.Logger; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +final class DispatcherImpl implements Dispatcher { + private final ExecuteThread[] threads; + private final List q = new LinkedList(); + + final Object ticket = new Object(); + + private boolean active = true; + + public DispatcherImpl(final StreamConfiguration conf) { + threads = new ExecuteThread[conf.getAsyncNumThreads()]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new ExecuteThread("Twitter4J Async Dispatcher", this, i); + threads[i].setDaemon(true); + threads[i].start(); + } + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + if (active) { + shutdown(); + } + } + }); + } + + @Override + public synchronized void invokeLater(final Runnable task) { + synchronized (q) { + q.add(task); + } + synchronized (ticket) { + ticket.notify(); + } + } + + public Runnable poll() { + while (active) { + synchronized (q) { + if (q.size() > 0) { + final Runnable task = q.remove(0); + if (task != null) return task; + } + } + synchronized (ticket) { + try { + ticket.wait(); + } catch (final InterruptedException ignore) { + } + } + } + return null; + } + + @Override + public synchronized void shutdown() { + if (active) { + active = false; + for (final ExecuteThread thread : threads) { + thread.shutdown(); + } + synchronized (ticket) { + ticket.notify(); + } + } + } +} + +class ExecuteThread extends Thread { + private static Logger logger = Logger.getLogger(DispatcherImpl.class); + DispatcherImpl q; + + private boolean alive = true; + + ExecuteThread(final String name, final DispatcherImpl q, final int index) { + super(name + "[" + index + "]"); + this.q = q; + } + + @Override + public void run() { + while (alive) { + final Runnable task = q.poll(); + if (task != null) { + try { + task.run(); + } catch (final Exception ex) { + logger.error("Got an exception while running a task:", ex); + } + } + } + } + + public void shutdown() { + alive = false; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/json/DataObjectFactoryUtil.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/json/DataObjectFactoryUtil.java new file mode 100644 index 00000000..d4d73471 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/internal/json/DataObjectFactoryUtil.java @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import twitter4j.json.DataObjectFactory; + +/** + * provides public access to package private methods of + * twitter4j.json.DataObjectFactory class.
+ * This class is not intended to be used by Twitter4J client. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.7 + */ +public class DataObjectFactoryUtil { + private static final Method CLEAR_THREAD_LOCAL_MAP; + + private static final Method REGISTER_JSON_OBJECT; + static { + final Method[] methods = DataObjectFactory.class.getDeclaredMethods(); + Method clearThreadLocalMap = null; + Method registerJSONObject = null; + for (final Method method : methods) { + if (method.getName().equals("clearThreadLocalMap")) { + clearThreadLocalMap = method; + clearThreadLocalMap.setAccessible(true); + } else if (method.getName().equals("registerJSONObject")) { + registerJSONObject = method; + registerJSONObject.setAccessible(true); + } + } + if (null == clearThreadLocalMap || null == registerJSONObject) throw new AssertionError(); + CLEAR_THREAD_LOCAL_MAP = clearThreadLocalMap; + REGISTER_JSON_OBJECT = registerJSONObject; + } + + private DataObjectFactoryUtil() { + throw new AssertionError("not intended to be instantiated."); + } + + /** + * provides a public access to {DAOFactory#clearThreadLocalMap} + */ + public static void clearThreadLocalMap() { + try { + CLEAR_THREAD_LOCAL_MAP.invoke(null); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new AssertionError(e); + } + } + + /** + * provides a public access to {DAOFactory#registerJSONObject} + */ + @SuppressWarnings("unchecked") + public static T registerJSONObject(final T key, final Object json) { + try { + return (T) REGISTER_JSON_OBJECT.invoke(null, key, json); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new AssertionError(e); + } + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/json/DataObjectFactory.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/json/DataObjectFactory.java new file mode 100644 index 00000000..1c8dd698 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/json/DataObjectFactory.java @@ -0,0 +1,595 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.json; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.AccountTotals; +import twitter4j.Category; +import twitter4j.DirectMessage; +import twitter4j.IDs; +import twitter4j.Location; +import twitter4j.OEmbed; +import twitter4j.Place; +import twitter4j.RateLimitStatus; +import twitter4j.Relationship; +import twitter4j.SavedSearch; +import twitter4j.Status; +import twitter4j.StatusDeletionNotice; +import twitter4j.Trend; +import twitter4j.Trends; +import twitter4j.TwitterException; +import twitter4j.User; +import twitter4j.UserList; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.7 + */ +@SuppressWarnings("unchecked") +public final class DataObjectFactory { + private static final Constructor statusConstructor; + + private static final Constructor userConstructor; + private static final Constructor relationshipConstructor; + private static final Constructor placeConstructor; + private static final Constructor savedSearchConstructor; + private static final Constructor trendConstructor; + private static final Constructor trendsConstructor; + private static final Constructor IDsConstructor; + private static final Method rateLimitStatusConstructor; + private static final Constructor categoryConstructor; + private static final Constructor directMessageConstructor; + private static final Constructor locationConstructor; + private static final Constructor userListConstructor; + private static final Constructor statusDeletionNoticeConstructor; + private static final Constructor accountTotalsConstructor; + private static final Constructor oembedConstructor; + static { + try { + statusConstructor = (Constructor) Class.forName("twitter4j.internal.json.StatusJSONImpl") + .getDeclaredConstructor(JSONObject.class); + statusConstructor.setAccessible(true); + + userConstructor = (Constructor) Class.forName("twitter4j.internal.json.UserJSONImpl") + .getDeclaredConstructor(JSONObject.class); + userConstructor.setAccessible(true); + + relationshipConstructor = (Constructor) Class.forName( + "twitter4j.internal.json.RelationshipJSONImpl").getDeclaredConstructor(JSONObject.class); + relationshipConstructor.setAccessible(true); + + placeConstructor = (Constructor) Class.forName("twitter4j.internal.json.PlaceJSONImpl") + .getDeclaredConstructor(JSONObject.class); + placeConstructor.setAccessible(true); + + savedSearchConstructor = (Constructor) Class.forName( + "twitter4j.internal.json.SavedSearchJSONImpl").getDeclaredConstructor(JSONObject.class); + savedSearchConstructor.setAccessible(true); + + trendConstructor = (Constructor) Class.forName("twitter4j.internal.json.TrendJSONImpl") + .getDeclaredConstructor(JSONObject.class); + trendConstructor.setAccessible(true); + + trendsConstructor = (Constructor) Class.forName("twitter4j.internal.json.TrendsJSONImpl") + .getDeclaredConstructor(String.class); + trendsConstructor.setAccessible(true); + + IDsConstructor = (Constructor) Class.forName("twitter4j.internal.json.IDsJSONImpl") + .getDeclaredConstructor(String.class); + IDsConstructor.setAccessible(true); + + rateLimitStatusConstructor = Class.forName("twitter4j.internal.json.RateLimitStatusJSONImpl") + .getDeclaredMethod("createRateLimitStatuses", JSONObject.class); + rateLimitStatusConstructor.setAccessible(true); + + categoryConstructor = (Constructor) Class.forName("twitter4j.internal.json.CategoryJSONImpl") + .getDeclaredConstructor(JSONObject.class); + categoryConstructor.setAccessible(true); + + directMessageConstructor = (Constructor) Class.forName( + "twitter4j.internal.json.DirectMessageJSONImpl").getDeclaredConstructor(JSONObject.class); + directMessageConstructor.setAccessible(true); + + locationConstructor = (Constructor) Class.forName("twitter4j.internal.json.LocationJSONImpl") + .getDeclaredConstructor(JSONObject.class); + locationConstructor.setAccessible(true); + + userListConstructor = (Constructor) Class.forName("twitter4j.internal.json.UserListJSONImpl") + .getDeclaredConstructor(JSONObject.class); + userListConstructor.setAccessible(true); + + statusDeletionNoticeConstructor = (Constructor) Class.forName( + "twitter4j.StatusDeletionNoticeImpl").getDeclaredConstructor(JSONObject.class); + statusDeletionNoticeConstructor.setAccessible(true); + + accountTotalsConstructor = (Constructor) Class.forName( + "twitter4j.internal.json.AccountTotalsJSONImpl").getDeclaredConstructor(JSONObject.class); + accountTotalsConstructor.setAccessible(true); + oembedConstructor = (Constructor) Class.forName("twitter4j.internal.json.OEmbedJSONImpl") + .getDeclaredConstructor(JSONObject.class); + oembedConstructor.setAccessible(true); + } catch (final NoSuchMethodException e) { + throw new ExceptionInInitializerError(e); + } catch (final ClassNotFoundException e) { + throw new ExceptionInInitializerError(e); + } + } + + @SuppressWarnings("rawtypes") + private static final ThreadLocal rawJsonMap = new ThreadLocal() { + @Override + protected Map initialValue() { + return new HashMap(); + } + }; + + private DataObjectFactory() { + throw new AssertionError("not intended to be instantiated."); + } + + /** + * Constructs an AccountTotals object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return AccountTotals + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.9 + */ + public static AccountTotals createAccountTotals(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return accountTotalsConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Category object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Category + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Category createCategory(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return categoryConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a DirectMessage object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return DirectMessage + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static DirectMessage createDirectMessage(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return directMessageConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a IDs object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return IDs + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static IDs createIDs(final String rawJSON) throws TwitterException { + try { + return IDsConstructor.newInstance(rawJSON); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Location object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Location + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Location createLocation(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return locationConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Construct an object from rawJSON string. This method may be called when + * you do not know what a given raw JSON string contains. It will do the + * work of determining what type of object the JSON represents, and + * constructing the respective object type. For example, if the JSON + * contents represents a Status, then a Status will be returned. If it + * represents a deletion notice, then a StatusDeletionNotice will be + * returned. The caller can simply use instanceof to handle the returned + * object as applicable. NOTE: the raw JSONObject will be returned in cases + * where there isn't a discrete respective object type that can be + * constructed. That way, the caller can at least have access to the JSON + * itself. + * + * @param rawJSON raw JSON form as String + * @return the respective constructed object, or the JSONObject in the case + * where we cannot determine the object type. + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.9 + */ + public static Object createObject(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + final JSONObjectType.Type jsonObjectType = JSONObjectType.determine(json); + switch (jsonObjectType) { + case SENDER: + return registerJSONObject( + directMessageConstructor.newInstance(json.getJSONObject("direct_message")), json); + case STATUS: + return registerJSONObject(statusConstructor.newInstance(json), json); + case DIRECT_MESSAGE: + return registerJSONObject( + directMessageConstructor.newInstance(json.getJSONObject("direct_message")), json); + case DELETE: + return registerJSONObject( + statusDeletionNoticeConstructor.newInstance(json.getJSONObject("delete").getJSONObject( + "status")), json); + case LIMIT: + // TODO: Perhaps there should be a TrackLimitationNotice + // object? + // The onTrackLimitationNotice method could take that as an + // arg. + return json; + case SCRUB_GEO: + return json; + default: + // The object type is unrecognized...just return the json + return json; + } + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs an OEmbed object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return OEmbed + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 3.0.2 + */ + public static OEmbed createOEmbed(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return oembedConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Place object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Place + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Place createPlace(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return placeConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a RateLimitStatus object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return RateLimitStatus + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Map createRateLimitStatus(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return (Map) rateLimitStatusConstructor.invoke( + Class.forName("twitter4j.internal.json.RateLimitStatusJSONImpl"), json); + } catch (final ClassNotFoundException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Relationship object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Relationship + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Relationship createRelationship(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return relationshipConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a SavedSearch object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return SavedSearch + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static SavedSearch createSavedSearch(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return savedSearchConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Status object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Status + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Status createStatus(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return statusConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Trend object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Trend + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Trend createTrend(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return trendConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a Trends object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return Trends + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static Trends createTrends(final String rawJSON) throws TwitterException { + try { + return trendsConstructor.newInstance(rawJSON); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new TwitterException(e); + } catch (final InvocationTargetException e) { + throw new AssertionError(e); + } + } + + /** + * Constructs a User object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return User + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static User createUser(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return userConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Constructs a UserList object from rawJSON string. + * + * @param rawJSON raw JSON form as String + * @return UserList + * @throws TwitterException when provided string is not a valid JSON string. + * @since Twitter4J 2.1.7 + */ + public static UserList createUserList(final String rawJSON) throws TwitterException { + try { + final JSONObject json = new JSONObject(rawJSON); + return userListConstructor.newInstance(json); + } catch (final InstantiationException e) { + throw new TwitterException(e); + } catch (final IllegalAccessException e) { + throw new AssertionError(e); + } catch (final InvocationTargetException e) { + throw new TwitterException(e); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /** + * Returns a raw JSON form of the provided object.
+ * Note that raw JSON forms can be retrieved only from the same thread + * invoked the last method call and will become inaccessible once another + * method call + * + * @param obj + * @return raw JSON + * @since Twitter4J 2.1.7 + */ + public static String getRawJSON(final Object obj) { + final Object json = rawJsonMap.get().get(obj); + if (json instanceof String) + return (String) json; + else if (json != null) // object must be instance of JSONObject + return json.toString(); + else + return null; + } + + /** + * clear raw JSON forms associated with the current thread.
+ * Currently this method is called indirectly by + * twitter4j.internal.util.DataObjectFactoryUtil, and should be called + * directly once *JSONImpl classes are migrated to twitter4j.json.* package. + * + * @since Twitter4J 2.1.7 + */ + static void clearThreadLocalMap() { + rawJsonMap.get().clear(); + } + + /** + * associate a raw JSON form to the current thread
+ * Currently this method is called indirectly by + * twitter4j.internal.util.DataObjectFactoryUtil, and should be called + * directly once *JSONImpl classes are migrated to twitter4j.json.* package. + * + * @since Twitter4J 2.1.7 + */ + static T registerJSONObject(final T key, final Object json) { + rawJsonMap.get().put(key, json); + return key; + } +} diff --git a/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/json/JSONObjectType.java b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/json/JSONObjectType.java new file mode 100644 index 00000000..ab33da76 --- /dev/null +++ b/firetweet.component.twitter4j.streaming/src/main/java/twitter4j/json/JSONObjectType.java @@ -0,0 +1,105 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.internal.logging.Logger; + +/** + * @author Dan Checkoway - dcheckoway at gmail.com + * @since Twitter4J 2.1.9 + */ +public final class JSONObjectType { + private static final Logger logger = Logger.getLogger(JSONObjectType.class); + + /** + * Determine the respective object type for a given JSONObject. This method + * inspects the object to figure out what type of object it represents. This + * is useful when processing JSON events of mixed type from a stream, in + * which case you may need to know what type of object to construct, or how + * to handle the event properly. + * + * @param json the JSONObject whose type should be determined + * @return the determined JSONObjectType, or null if not recognized + */ + public static Type determine(final JSONObject json) { + // This code originally lived in AbstractStreamImplementation. + // I've moved it in here to expose it as a public encapsulation of + // the object type determination logic. + if (!json.isNull("sender")) + return Type.SENDER; + else if (!json.isNull("text")) + return Type.STATUS; + else if (!json.isNull("direct_message")) + return Type.DIRECT_MESSAGE; + else if (!json.isNull("delete")) + return Type.DELETE; + else if (!json.isNull("limit")) + return Type.LIMIT; + else if (!json.isNull("warning")) + return Type.STALL_WARNING; + else if (!json.isNull("scrub_geo")) + return Type.SCRUB_GEO; + else if (!json.isNull("friends")) + return Type.FRIENDS; + else if (!json.isNull("event")) { + String event; + try { + event = json.getString("event"); + if ("favorite".equals(event)) + return Type.FAVORITE; + else if ("unfavorite".equals(event)) + return Type.UNFAVORITE; + else if ("follow".equals(event)) + return Type.FOLLOW; + else if ("unfollow".equals(event)) + return Type.UNFOLLOW; + else if (event.startsWith("list")) { + if ("list_member_added".equals(event)) + return Type.USER_LIST_MEMBER_ADDED; + else if ("list_member_removed".equals(event)) + return Type.USER_LIST_MEMBER_DELETED; + else if ("list_user_subscribed".equals(event)) + return Type.USER_LIST_SUBSCRIBED; + else if ("list_user_unsubscribed".equals(event)) + return Type.USER_LIST_UNSUBSCRIBED; + else if ("list_created".equals(event)) + return Type.USER_LIST_CREATED; + else if ("list_updated".equals(event)) + return Type.USER_LIST_UPDATED; + else if ("list_destroyed".equals(event)) return Type.USER_LIST_DESTROYED; + } else if ("user_update".equals(event)) + return Type.USER_UPDATE; + else if ("block".equals(event)) + return Type.BLOCK; + else if ("unblock".equals(event)) return Type.UNBLOCK; + } catch (final JSONException jsone) { + try { + logger.warn("Failed to get event element: ", json.toString(2)); + } catch (final JSONException ignore) { + } + } + } else if (!json.isNull("disconnect")) return Type.DISCONNECTION; + return Type.UNKNOWN; + } + + public enum Type { + SENDER, STATUS, DIRECT_MESSAGE, DELETE, LIMIT, STALL_WARNING, SCRUB_GEO, FRIENDS, FAVORITE, UNFAVORITE, FOLLOW, UNFOLLOW, USER_LIST_MEMBER_ADDED, USER_LIST_MEMBER_DELETED, USER_LIST_SUBSCRIBED, USER_LIST_UNSUBSCRIBED, USER_LIST_CREATED, USER_LIST_UPDATED, USER_LIST_DESTROYED, USER_UPDATE, BLOCK, UNBLOCK, DISCONNECTION, UNKNOWN + } +} diff --git a/firetweet.component.twitter4j/.gitignore b/firetweet.component.twitter4j/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.component.twitter4j/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.component.twitter4j/build.gradle b/firetweet.component.twitter4j/build.gradle new file mode 100644 index 00000000..a166550a --- /dev/null +++ b/firetweet.component.twitter4j/build.gradle @@ -0,0 +1,40 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.component.twitter4j/src/main/AndroidManifest.xml b/firetweet.component.twitter4j/src/main/AndroidManifest.xml new file mode 100644 index 00000000..7f3c924e --- /dev/null +++ b/firetweet.component.twitter4j/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/AccountSettings.java b/firetweet.component.twitter4j/src/main/java/twitter4j/AccountSettings.java new file mode 100644 index 00000000..f9328ba1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/AccountSettings.java @@ -0,0 +1,88 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +public interface AccountSettings extends TwitterResponse, Serializable { + /** + * Returns the language used to render Twitter's UII for this user. + * + * @return the language ISO 639-1 representation + */ + String getLanguage(); + + /** + * Returns sleep end time. + * + * @return sleep end time + */ + String getSleepEndTime(); + + /** + * Returns sleep start time. + * + * @return sleep start time + */ + String getSleepStartTime(); + + /** + * Returns the timezone configured for this user. + * + * @return the timezone (formated as a Rails TimeZone name) + */ + TimeZone getTimeZone(); + + /** + * Return the user's trend locations + * + * @return the user's trend locations + */ + Location[] getTrendLocations(); + + /** + * Returns true if the wants to always access twitter using HTTPS. + * + * @return true if the wants to always access twitter using HTTPS + */ + boolean isAlwaysUseHttps(); + + /** + * Returns true if the user is discoverable by email. + * + * @return true if the user is discoverable by email + */ + boolean isDiscoverableByEmail(); + + /** + * Return true if the user is enabling geo location + * + * @return true if the user is enabling geo location + */ + boolean isGeoEnabled(); + + /** + * Returns true if the user enabled sleep time. + * + * @return true if the user enabled sleep time + */ + boolean isSleepTimeEnabled(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/AccountTotals.java b/firetweet.component.twitter4j/src/main/java/twitter4j/AccountTotals.java new file mode 100644 index 00000000..d190dd79 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/AccountTotals.java @@ -0,0 +1,53 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +public interface AccountTotals extends TwitterResponse, Serializable { + /** + * Returns the number of total favorites. + * + * @return the number of total favorites + */ + int getFavorites(); + + /** + * Returns the number of total followers. + * + * @return the number of total followers + */ + int getFollowers(); + + /** + * Returns the number of total friends. + * + * @return the number of total friends + */ + int getFriends(); + + /** + * Returns the number of total updates. + * + * @return the number of total updates + */ + int getUpdates(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Activity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Activity.java new file mode 100644 index 00000000..e00e28e3 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Activity.java @@ -0,0 +1,71 @@ +package twitter4j; + +import java.io.Serializable; +import java.util.Date; + +public interface Activity extends TwitterResponse, Comparable, Serializable { + + public Action getAction(); + + public Date getCreatedAt(); + + public long getMaxPosition(); + + public long getMinPosition(); + + public User[] getSources(); + + public int getSourcesSize(); + + public int getTargetObjectsSize(); + + public Status[] getTargetObjectStatuses(); + + public UserList[] getTargetObjectUserLists(); + + public int getTargetsSize(); + + public Status[] getTargetStatuses(); + + public UserList[] getTargetUserLists(); + + public User[] getTargetUsers(); + + public static enum Action implements Serializable { + FAVORITE(0x1), FOLLOW(0x2), MENTION(0x3), REPLY(0x4), RETWEET(0x5), LIST_MEMBER_ADDED(0x06), + LIST_CREATED(0x07), FAVORITED_RETWEET(0x08), RETWEETED_RETWEET(0x09); + + public final static int ACTION_FAVORITE = 0x01; + public final static int ACTION_FOLLOW = 0x02; + public final static int ACTION_MENTION = 0x03; + public final static int ACTION_REPLY = 0x04; + public final static int ACTION_RETWEET = 0x05; + public final static int ACTION_LIST_MEMBER_ADDED = 0x06; + public final static int ACTION_LIST_CREATED = 0x07; + public final static int ACTION_FAVORITED_RETWEET = 0x08; + public final static int ACTION_RETWEETED_RETWEET = 0x09; + + private final int actionId; + + private Action(final int action) { + actionId = action; + } + + public int getActionId() { + return actionId; + } + + public static Action fromString(final String string) { + if ("favorite".equalsIgnoreCase(string)) return FAVORITE; + if ("follow".equalsIgnoreCase(string)) return FOLLOW; + if ("mention".equalsIgnoreCase(string)) return MENTION; + if ("reply".equalsIgnoreCase(string)) return REPLY; + if ("retweet".equalsIgnoreCase(string)) return RETWEET; + if ("list_member_added".equalsIgnoreCase(string)) return LIST_MEMBER_ADDED; + if ("list_created".equalsIgnoreCase(string)) return LIST_CREATED; + if ("favorited_retweet".equalsIgnoreCase(string)) return FAVORITED_RETWEET; + if ("retweeted_retweet".equalsIgnoreCase(string)) return RETWEETED_RETWEET; + throw new IllegalArgumentException("Unknown action " + string); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/CardEntity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/CardEntity.java new file mode 100644 index 00000000..ac9f3aaf --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/CardEntity.java @@ -0,0 +1,69 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * Created by mariotaku on 14/12/31. + */ +public interface CardEntity extends Serializable { + + String getName(); + + User[] gerUsers(); + + BindingValue getBindingValue(String key); + + BindingValue[] getBindingValues(); + + public interface BindingValue extends Serializable { + + public static final String TYPE_STRING = "STRING"; + public static final String TYPE_IMAGE = "IMAGE"; + public static final String TYPE_USER = "USER"; + public static final String TYPE_BOOLEAN = "BOOLEAN"; + + String getName(); + + String getType(); + } + + + public interface UserValue extends BindingValue { + long getUserId(); + } + + public interface StringValue extends BindingValue { + String getValue(); + } + + public interface BooleanValue extends BindingValue { + boolean getValue(); + } + + public interface ImageValue extends BindingValue { + int getWidth(); + + int getHeight(); + + String getUrl(); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Category.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Category.java new file mode 100644 index 00000000..304839d7 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Category.java @@ -0,0 +1,31 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public interface Category extends Serializable { + String getName(); + + int getSize(); + + String getSlug(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/CursorPaging.java b/firetweet.component.twitter4j/src/main/java/twitter4j/CursorPaging.java new file mode 100644 index 00000000..3bcc2fc9 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/CursorPaging.java @@ -0,0 +1,139 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.util.ArrayList; +import java.util.List; + +import twitter4j.http.HttpParameter; + +/** + * Controls pagination.
+ * It is possible to use the same Paging instance in a multi-threaded context + * only if the instance is treated immutably.
+ * But basically instance of this class is NOT thread safe. A client should + * instantiate Paging class per thread.
+ * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class CursorPaging { + private int count = -1; + private long cursor = -1; + + static final String COUNT = "count"; + static final String CURSOR = "cursor"; + + private static HttpParameter[] NULL_PARAMETER_ARRAY = new HttpParameter[0]; + private static List NULL_PARAMETER_LIST = new ArrayList(0); + + public CursorPaging() { + } + + public CursorPaging(final int count) { + setCount(count); + } + + public CursorPaging(final long cursor) { + setCursor(cursor); + } + + public CursorPaging(final long cursor, final int count) { + setCursor(cursor); + setCount(count); + } + + public CursorPaging count(final int count) { + setCount(count); + return this; + } + + public CursorPaging cursor(final long cursor) { + setCursor(cursor); + return this; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof CursorPaging)) return false; + final CursorPaging paging = (CursorPaging) o; + if (count != paging.count) return false; + if (cursor != paging.cursor) return false; + return true; + } + + public int getCount() { + return count; + } + + public long getCursor() { + return cursor; + } + + @Override + public int hashCode() { + int result = count; + result = 31 * result + (int) (cursor ^ cursor >>> 32); + return result; + } + + public void setCount(final int count) { + if (count < 1) throw new IllegalArgumentException("count should be positive integer. passed:" + count); + this.count = count; + } + + public void setCursor(final long cursor) { + if (cursor < 1 && cursor != -1) + throw new IllegalArgumentException("cursor should be -1 or positive integer. passed:" + cursor); + this.cursor = cursor; + } + + @Override + public String toString() { + return "Paging{" + "cursor=" + cursor + ", count=" + count + '}'; + } + + /* package */HttpParameter[] asPostParameterArray() { + final List list = asPostParameterList(); + if (list.size() == 0) return NULL_PARAMETER_ARRAY; + return list.toArray(new HttpParameter[list.size()]); + } + + /** + * Converts the pagination parameters into a List of PostParameter.
+ * This method also Validates the preset parameters, and throws + * IllegalStateException if any unsupported parameter is set. + * + * @return list of PostParameter + */ + /* package */List asPostParameterList() { + final List pagingParams = new ArrayList(); + if (cursor > 0 || cursor == -1) { + pagingParams.add(new HttpParameter(CURSOR, cursor)); + } + if (count > 0) { + pagingParams.add(new HttpParameter(COUNT, count)); + } + if (pagingParams.size() == 0) + return NULL_PARAMETER_LIST; + else + return pagingParams; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/CursorSupport.java b/firetweet.component.twitter4j/src/main/java/twitter4j/CursorSupport.java new file mode 100644 index 00000000..e3094710 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/CursorSupport.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface CursorSupport { + /** + * @since Twitter4J 2.2.3 + */ + long START = -1L; + + /** + * @since Twitter4J 2.0.10 + */ + long getNextCursor(); + + /** + * @since Twitter4J 2.0.10 + */ + long getPreviousCursor(); + + /** + * @since Twitter4J 2.0.10 + */ + boolean hasNext(); + + /** + * @since Twitter4J 2.0.10 + */ + boolean hasPrevious(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/DirectMessage.java b/firetweet.component.twitter4j/src/main/java/twitter4j/DirectMessage.java new file mode 100644 index 00000000..f75bfb1a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/DirectMessage.java @@ -0,0 +1,52 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.util.Date; + +/** + * A data interface representing sent/received direct message. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface DirectMessage extends TwitterResponse, EntitySupport { + + /** + * @return created_at + * @since Twitter4J 1.1.0 + */ + Date getCreatedAt(); + + long getId(); + + String getRawText(); + + User getRecipient(); + + long getRecipientId(); + + String getRecipientScreenName(); + + User getSender(); + + long getSenderId(); + + String getSenderScreenName(); + + String getText(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/EntitySupport.java b/firetweet.component.twitter4j/src/main/java/twitter4j/EntitySupport.java new file mode 100644 index 00000000..dbc02e46 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/EntitySupport.java @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.5 + */ +public interface EntitySupport extends Serializable { + /** + * Returns an array if hashtag mentioned in the tweet, or null if no hashtag + * were mentioned. + * + * @return An array of Hashtag mentioned in the tweet. + * @since Twitter4J 2.1.9 + */ + HashtagEntity[] getHashtagEntities(); + + /** + * Returns an array of MediaEntities if media are available in the tweet, + * or null if no media is included in the tweet. + * + * @return an array of MediaEntities. + * @since Twitter4J 2.2.3 + */ + MediaEntity[] getMediaEntities(); + + /** + * Returns an array if URLEntity mentioned in the tweet, or null if no URLs + * were mentioned. + * + * @return An array of URLEntity mentioned in the tweet. + * @since Twitter4J 2.1.9 + */ + URLEntity[] getURLEntities(); + + /** + * Returns an array of user mentions in the tweet, or null if no users were + * mentioned. + * + * @return An array of user mention entities in the tweet. + * @since Twitter4J 2.1.9 + */ + UserMentionEntity[] getUserMentionEntities(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/ExceptionDiagnosis.java b/firetweet.component.twitter4j/src/main/java/twitter4j/ExceptionDiagnosis.java new file mode 100644 index 00000000..4ac416ba --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/ExceptionDiagnosis.java @@ -0,0 +1,106 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +final class ExceptionDiagnosis { + int stackLineHash; + int lineNumberHash; + String hexString = ""; + Throwable th; + + ExceptionDiagnosis(final Throwable th) { + this(th, new String[] {}); + } + + ExceptionDiagnosis(final Throwable th, final String[] inclusionFilter) { + this.th = th; + + final StackTraceElement[] stackTrace = th.getStackTrace(); + stackLineHash = 0; + lineNumberHash = 0; + for (int i = stackTrace.length - 1; i >= 0; i--) { + final StackTraceElement line = stackTrace[i]; + for (final String filter : inclusionFilter) { + if (line.getClassName().startsWith(filter)) { + final int hash = line.getClassName().hashCode() + line.getMethodName().hashCode(); + stackLineHash = 31 * stackLineHash + hash; + lineNumberHash = 31 * lineNumberHash + line.getLineNumber(); + break; + } + } + } + hexString += toHexString(stackLineHash) + "-" + toHexString(lineNumberHash); + if (th.getCause() != null) { + hexString += " " + new ExceptionDiagnosis(th.getCause(), inclusionFilter).asHexString(); + } + + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ExceptionDiagnosis that = (ExceptionDiagnosis) o; + + if (lineNumberHash != that.lineNumberHash) return false; + if (stackLineHash != that.stackLineHash) return false; + + return true; + } + + @Override + public int hashCode() { + int result = stackLineHash; + result = 31 * result + lineNumberHash; + return result; + } + + @Override + public String toString() { + return "ExceptionDiagnosis{" + "stackLineHash=" + stackLineHash + ", lineNumberHash=" + lineNumberHash + '}'; + } + + private String toHexString(final int value) { + final String str = "0000000" + Integer.toHexString(value); + return str.substring(str.length() - 8, str.length()); + } + + String asHexString() { + return hexString; + } + + int getLineNumberHash() { + return lineNumberHash; + } + + String getLineNumberHashAsHex() { + return toHexString(lineNumberHash); + } + + int getStackLineHash() { + return stackLineHash; + } + + String getStackLineHashAsHex() { + return toHexString(stackLineHash); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/ExtendedEntitySupport.java b/firetweet.component.twitter4j/src/main/java/twitter4j/ExtendedEntitySupport.java new file mode 100644 index 00000000..5ad152da --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/ExtendedEntitySupport.java @@ -0,0 +1,37 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +/** + * @author Mariotaku Lee + * @since Twitter4J 2.2.5 + */ +public interface ExtendedEntitySupport extends EntitySupport { + + /** + * Returns an array of MediaEntities if media are available in the tweet, + * or null if no media is included in the tweet. + * + * @return an array of MediaEntities. + * @since Twitter4J 2.2.3 + */ + MediaEntity[] getExtendedMediaEntities(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Friendship.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Friendship.java new file mode 100644 index 00000000..2eca3715 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Friendship.java @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +public interface Friendship { + long getId(); + + String getName(); + + String getScreenName(); + + boolean isFollowedBy(); + + boolean isFollowing(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/GeoLocation.java b/firetweet.component.twitter4j/src/main/java/twitter4j/GeoLocation.java new file mode 100644 index 00000000..95531c90 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/GeoLocation.java @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * A data class representing geo location. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public class GeoLocation implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 4603460402828968366L; + protected double latitude; + protected double longitude; + + /** + * Creates a GeoLocation instance + * + * @param latitude the latitude + * @param longitude the longitude + */ + public GeoLocation(final double latitude, final double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + /* For serialization purposes only. */ + /* package */GeoLocation() { + + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof GeoLocation)) return false; + + final GeoLocation that = (GeoLocation) o; + + if (Double.compare(that.getLatitude(), latitude) != 0) return false; + if (Double.compare(that.getLongitude(), longitude) != 0) return false; + + return true; + } + + /** + * returns the latitude of the geo location + * + * @return the latitude + */ + public double getLatitude() { + return latitude; + } + + /** + * returns the longitude of the geo location + * + * @return the longitude + */ + public double getLongitude() { + return longitude; + } + + @Override + public int hashCode() { + int result; + long temp; + temp = latitude != +0.0d ? Double.doubleToLongBits(latitude) : 0L; + result = (int) (temp ^ temp >>> 32); + temp = longitude != +0.0d ? Double.doubleToLongBits(longitude) : 0L; + result = 31 * result + (int) (temp ^ temp >>> 32); + return result; + } + + @Override + public String toString() { + return "GeoLocation{" + "latitude=" + latitude + ", longitude=" + longitude + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/GeoQuery.java b/firetweet.component.twitter4j/src/main/java/twitter4j/GeoQuery.java new file mode 100644 index 00000000..282ae448 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/GeoQuery.java @@ -0,0 +1,198 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.util.ArrayList; +import java.util.List; + +import twitter4j.http.HttpParameter; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public final class GeoQuery { + + private final GeoLocation location; + private final String ip; + private String accuracy; + private String granularity; + private int maxResults; + public static final String NEIGHBORHOOD = "neighborhood"; + public static final String CITY = "city"; + + /** + * Creates a GeoQuery with the specified location + * + * @param location + */ + public GeoQuery(final GeoLocation location) { + this.location = location; + ip = null; + } + + /** + * Creates a GeoQuery with the specified IP address + * + * @param ip IP address + */ + public GeoQuery(final String ip) { + this.ip = ip; + location = null; + } + + public GeoQuery accuracy(final String accuracy) { + setAccuracy(accuracy); + return this; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final GeoQuery geoQuery = (GeoQuery) o; + + if (maxResults != geoQuery.maxResults) return false; + if (accuracy != null ? !accuracy.equals(geoQuery.accuracy) : geoQuery.accuracy != null) return false; + if (granularity != null ? !granularity.equals(geoQuery.granularity) : geoQuery.granularity != null) + return false; + if (ip != null ? !ip.equals(geoQuery.ip) : geoQuery.ip != null) return false; + if (location != null ? !location.equals(geoQuery.location) : geoQuery.location != null) return false; + + return true; + } + + public String getAccuracy() { + return accuracy; + } + + public String getGranularity() { + return granularity; + } + + public String getIp() { + return ip; + } + + public GeoLocation getLocation() { + return location; + } + + public int getMaxResults() { + return maxResults; + } + + public GeoQuery granularity(final String granularity) { + setGranularity(granularity); + return this; + } + + @Override + public int hashCode() { + int result = location != null ? location.hashCode() : 0; + result = 31 * result + (ip != null ? ip.hashCode() : 0); + result = 31 * result + (accuracy != null ? accuracy.hashCode() : 0); + result = 31 * result + (granularity != null ? granularity.hashCode() : 0); + result = 31 * result + maxResults; + return result; + } + + public GeoQuery maxResults(final int maxResults) { + setMaxResults(maxResults); + return this; + } + + /** + * Sets a hint on the "region" in which to search. If a number, then this is + * a radius in meters, but it can also take a string that is suffixed with + * ft to specify feet. If this is not passed in, then it is assumed to be + * 0m. If coming from a device, in practice, this value is whatever accuracy + * the device has measuring its location (whether it be coming from a GPS, + * WiFi triangulation, etc.). + * + * @param accuracy a hint on the "region" in which to search. + */ + public void setAccuracy(final String accuracy) { + this.accuracy = accuracy; + } + + /** + * Sets the minimal granularity of data to return. If this is not passed in, + * then neighborhood is assumed. city can also be passed. + * + * @param granularity the minimal granularity of data to return + */ + public void setGranularity(final String granularity) { + this.granularity = granularity; + } + + /** + * Sets a hint as to the number of results to return. This does not + * guarantee that the number of results returned will equal max_results, but + * instead informs how many "nearby" results to return. Ideally, only pass + * in the number of places you intend to display to the user here. + * + * @param maxResults A hint as to the number of results to return. + */ + public void setMaxResults(final int maxResults) { + this.maxResults = maxResults; + } + + @Override + public String toString() { + return "GeoQuery{" + "location=" + location + ", ip='" + ip + '\'' + ", accuracy='" + accuracy + '\'' + + ", granularity='" + granularity + '\'' + ", maxResults=" + maxResults + '}'; + } + + private void appendParameter(final String name, final double value, final List params) { + params.add(new HttpParameter(name, String.valueOf(value))); + } + + private void appendParameter(final String name, final int value, final List params) { + if (0 < value) { + params.add(new HttpParameter(name, String.valueOf(value))); + } + } + + private void appendParameter(final String name, final String value, final List params) { + if (value != null) { + params.add(new HttpParameter(name, value)); + } + } + + /* package */HttpParameter[] asHttpParameterArray() { + final ArrayList params = new ArrayList(); + if (location != null) { + appendParameter("lat", location.getLatitude(), params); + appendParameter("long", location.getLongitude(), params); + + } + if (ip != null) { + appendParameter("ip", ip, params); + + } + appendParameter("accuracy", accuracy, params); + appendParameter("granularity", granularity, params); + appendParameter("max_results", maxResults, params); + final HttpParameter[] paramArray = new HttpParameter[params.size()]; + return params.toArray(paramArray); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/HashtagEntity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/HashtagEntity.java new file mode 100644 index 00000000..23ed2c1b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/HashtagEntity.java @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * A data interface representing one single Hashtag entity. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +public interface HashtagEntity extends Serializable { + /** + * Returns the index of the end character of the hashtag. + * + * @return the index of the end character of the hashtag + */ + int getEnd(); + + /** + * Returns the index of the start character of the hashtag. + * + * @return the index of the start character of the hashtag + */ + int getStart(); + + /** + * Returns the text of the hashtag without #. + * + * @return the text of the hashtag + */ + String getText(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/IDs.java b/firetweet.component.twitter4j/src/main/java/twitter4j/IDs.java new file mode 100644 index 00000000..679d2d85 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/IDs.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * A data interface representing array of numeric IDs. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface IDs extends TwitterResponse, CursorSupport { + long[] getIDs(); + + @Override + long getNextCursor(); + + @Override + long getPreviousCursor(); + + @Override + boolean hasNext(); + + @Override + boolean hasPrevious(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Location.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Location.java new file mode 100644 index 00000000..f0387d9f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Location.java @@ -0,0 +1,36 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface Location { + String getCountryCode(); + + String getCountryName(); + + String getName(); + + int getPlaceCode(); + + String getPlaceName(); + + String getURL(); + + int getWoeid(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/MediaEntity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/MediaEntity.java new file mode 100644 index 00000000..0cb583cf --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/MediaEntity.java @@ -0,0 +1,112 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.net.URL; +import java.util.Map; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.3 + */ +public interface MediaEntity extends URLEntity, Serializable { + /** + * Returns the id of the media. + * + * @return the id of the media + */ + long getId(); + + /** + * Returns the media URL. + * + * @return the media URL + */ + String getMediaURL(); + + /** + * Returns the media secure URL. + * + * @return the media secure URL + */ + String getMediaURLHttps(); + + /** + * Returns size variations of the media. + * + * @return size variations of the media + */ + Map getSizes(); + + /** + * Returns the media type ("photo"). + * + * @return the media type ("photo"). + */ + Type getType(); + + enum Type { + PHOTO, VIDEO, UNKNOWN; + + public static Type parse(String typeString) { + if ("photo".equalsIgnoreCase(typeString)) { + return PHOTO; + } else if ("video".equalsIgnoreCase(typeString)) { + return VIDEO; + } + return UNKNOWN; + } + } + + VideoInfo getVideoInfo(); + + interface VideoInfo extends Serializable { + + Variant[] getVariants(); + + long[] getAspectRatio(); + + long getDuration(); + + interface Variant extends Serializable { + + String getContentType(); + + String getUrl(); + + long getBitrate(); + } + + } + + interface Size extends Serializable { + Integer THUMB = 0; + Integer SMALL = 1; + Integer MEDIUM = 2; + Integer LARGE = 3; + int FIT = 100; + int CROP = 101; + + int getHeight(); + + int getResize(); + + int getWidth(); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/MediaUploadResponse.java b/firetweet.component.twitter4j/src/main/java/twitter4j/MediaUploadResponse.java new file mode 100644 index 00000000..b4c364d9 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/MediaUploadResponse.java @@ -0,0 +1,19 @@ +package twitter4j; + +public interface MediaUploadResponse extends TwitterResponse { + + public long getId(); + + public Image getImage(); + + public long getSize(); + + public interface Image { + + public int getHeight(); + + public String getImageType(); + + public int getWidth(); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/OEmbed.java b/firetweet.component.twitter4j/src/main/java/twitter4j/OEmbed.java new file mode 100644 index 00000000..9b7b98ce --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/OEmbed.java @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 3.0.2 + * @see oEmded + */ +public interface OEmbed extends TwitterResponse, Serializable { + /** + * The name of the author/owner of the resource. + * + * @return The name of the author/owner of the resource. + */ + String getAuthorName(); + + /** + * A URL for the author/owner of the resource. + * + * @return A URL for the author/owner of the resource. + */ + String getAuthorURL(); + + // provier_url is always "http://twitter.com/" + // String getProviderURL(); + + /** + * The suggested cache lifetime for this resource, in seconds. Consumers may + * choose to use this value or not. + * + * @return The suggested cache lifetime for this resource, in seconds. + * Consumers may choose to use this value or not. + */ + long getCacheAge(); + + // provider_name is always "Twitter" + // String getProviderName(); + + /** + * The HTML required to display the resource. The HTML should have no + * padding or margins. Consumers may wish to load the HTML in an off-domain + * iframe to avoid XSS vulnerabilities. The markup should be valid XHTML 1.0 + * Basic. + * + * @return The HTML required to display the resource. + */ + String getHtml(); + + // type is always "rich" + // String getType(); + + /** + * The url of the resource provider.
+ * The source URL of the image. Consumers should be able to insert this URL + * into an <img> element. Only HTTP and HTTPS URLs are valid. + * + * @return The url of the resource provider. + */ + String getURL(); + + /** + * The oEmbed version number. + * + * @return The oEmbed version number. + */ + String getVersion(); + + /** + * The width in pixels of the image specified in the url parameter. + * + * @return The width in pixels of the image specified in the url parameter. + */ + int getWidth(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/OEmbedRequest.java b/firetweet.component.twitter4j/src/main/java/twitter4j/OEmbedRequest.java new file mode 100644 index 00000000..d29b9fd0 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/OEmbedRequest.java @@ -0,0 +1,189 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import twitter4j.http.HttpParameter; +import twitter4j.internal.util.InternalStringUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 3.0.2 + */ +public final class OEmbedRequest implements Serializable { + private static final long serialVersionUID = -4330607167106242987L; + private final long statusId; + private final String url; + private int maxWidth; + private boolean hideMedia = true; + private boolean hideThread = true; + private boolean omitScript = false; + private Align align = Align.NONE; + private String[] related = {}; + private String lang; + + OEmbedRequest(final long statusId, final String url) { + this.statusId = statusId; + this.url = url; + } + + public OEmbedRequest align(final Align align) { + this.align = align; + return this; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final OEmbedRequest that = (OEmbedRequest) o; + + if (hideMedia != that.hideMedia) return false; + if (hideThread != that.hideThread) return false; + if (maxWidth != that.maxWidth) return false; + if (omitScript != that.omitScript) return false; + if (statusId != that.statusId) return false; + if (align != that.align) return false; + if (lang != null ? !lang.equals(that.lang) : that.lang != null) return false; + if (!Arrays.equals(related, that.related)) return false; + if (url != null ? !url.equals(that.url) : that.url != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (statusId ^ statusId >>> 32); + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + maxWidth; + result = 31 * result + (hideMedia ? 1 : 0); + result = 31 * result + (hideThread ? 1 : 0); + result = 31 * result + (omitScript ? 1 : 0); + result = 31 * result + (align != null ? align.hashCode() : 0); + result = 31 * result + (related != null ? Arrays.hashCode(related) : 0); + result = 31 * result + (lang != null ? lang.hashCode() : 0); + return result; + } + + public OEmbedRequest HideMedia(final boolean hideMedia) { + this.hideMedia = hideMedia; + return this; + } + + public OEmbedRequest HideThread(final boolean hideThread) { + this.hideThread = hideThread; + return this; + } + + public OEmbedRequest lang(final String lang) { + this.lang = lang; + return this; + } + + public OEmbedRequest MaxWidth(final int maxWidth) { + this.maxWidth = maxWidth; + return this; + } + + public OEmbedRequest omitScript(final boolean omitScript) { + this.omitScript = omitScript; + return this; + } + + public OEmbedRequest related(final String[] related) { + this.related = related; + return this; + } + + public void setAlign(final Align align) { + this.align = align; + } + + public void setHideMedia(final boolean hideMedia) { + this.hideMedia = hideMedia; + } + + public void setHideThread(final boolean hideThread) { + this.hideThread = hideThread; + } + + public void setLang(final String lang) { + this.lang = lang; + } + + public void setMaxWidth(final int maxWidth) { + this.maxWidth = maxWidth; + } + + public void setOmitScript(final boolean omitScript) { + this.omitScript = omitScript; + } + + public void setRelated(final String[] related) { + this.related = related; + } + + @Override + public String toString() { + return "OEmbedRequest{" + "statusId=" + statusId + ", url='" + url + '\'' + ", maxWidth=" + maxWidth + + ", hideMedia=" + hideMedia + ", hideThread=" + hideThread + ", omitScript=" + omitScript + ", align=" + + align + ", related=" + (related == null ? null : Arrays.asList(related)) + ", lang='" + lang + '\'' + + '}'; + } + + private void appendParameter(final String name, final long value, final List params) { + if (0 <= value) { + params.add(new HttpParameter(name, String.valueOf(value))); + } + } + + private void appendParameter(final String name, final String value, final List params) { + if (value != null) { + params.add(new HttpParameter(name, value)); + } + } + + /* package */HttpParameter[] asHttpParameterArray() { + final ArrayList params = new ArrayList(12); + appendParameter("id", statusId, params); + appendParameter("url", url, params); + appendParameter("maxwidth", maxWidth, params); + params.add(new HttpParameter("hide_media", hideMedia)); + params.add(new HttpParameter("hide_thread", hideThread)); + params.add(new HttpParameter("omit_script", omitScript)); + params.add(new HttpParameter("align", align.name().toLowerCase(Locale.US))); + if (related.length > 0) { + appendParameter("related", InternalStringUtil.join(related), params); + } + appendParameter("lang", lang, params); + final HttpParameter[] paramArray = new HttpParameter[params.size()]; + return params.toArray(paramArray); + } + + public enum Align { + LEFT, CENTER, RIGHT, NONE + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/PageableResponseList.java b/firetweet.component.twitter4j/src/main/java/twitter4j/PageableResponseList.java new file mode 100644 index 00000000..8898a0c5 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/PageableResponseList.java @@ -0,0 +1,29 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +/** + * ResponseList with cursor support. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface PageableResponseList extends ResponseList, CursorSupport { + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Paging.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Paging.java new file mode 100644 index 00000000..94af0b8b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Paging.java @@ -0,0 +1,243 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.util.ArrayList; +import java.util.List; + +import twitter4j.http.HttpParameter; + +/** + * Controls pagination.
+ * It is possible to use the same Paging instance in a multi-threaded context + * only if the instance is treated immutably.
+ * But basically instance of this class is NOT thread safe. A client should + * instantiate Paging class per thread.
+ * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class Paging { + private int page = -1; + private int count = -1; + private long sinceId = -1; + private long maxId = -1; + + // since only + static char[] S = new char[] { 's' }; + // since, max_id, count, page + static char[] SMCP = new char[] { 's', 'm', 'c', 'p' }; + + static final String COUNT = "count"; + // somewhat GET list statuses requires "per_page" instead of "count" + // @see GET + // :user/lists/:id/statuses | Twitter Developers + static final String PER_PAGE = "per_page"; + + private static HttpParameter[] NULL_PARAMETER_ARRAY = new HttpParameter[0]; + + private static List NULL_PARAMETER_LIST = new ArrayList(0); + + public Paging() { + } + + public Paging(final int page) { + setPage(page); + } + + public Paging(final int page, final int count) { + this(page); + setCount(count); + } + + public Paging(final int page, final int count, final long sinceId) { + this(page, count); + setSinceId(sinceId); + } + + public Paging(final int page, final int count, final long sinceId, final long maxId) { + this(page, count, sinceId); + setMaxId(maxId); + } + + public Paging(final int page, final long sinceId) { + this(page); + setSinceId(sinceId); + } + + public Paging(final long sinceId) { + setSinceId(sinceId); + } + + public Paging count(final int count) { + setCount(count); + return this; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Paging)) return false; + + final Paging paging = (Paging) o; + + if (count != paging.count) return false; + if (maxId != paging.maxId) return false; + if (page != paging.page) return false; + if (sinceId != paging.sinceId) return false; + + return true; + } + + public int getCount() { + return count; + } + + public long getMaxId() { + return maxId; + } + + public int getPage() { + return page; + } + + public long getSinceId() { + return sinceId; + } + + @Override + public int hashCode() { + int result = page; + result = 31 * result + count; + result = 31 * result + (int) (sinceId ^ sinceId >>> 32); + result = 31 * result + (int) (maxId ^ maxId >>> 32); + return result; + } + + public Paging maxId(final long maxId) { + setMaxId(maxId); + return this; + } + + public void setCount(final int count) { + if (count < 1) throw new IllegalArgumentException("count should be positive integer. passed:" + count); + this.count = count; + } + + public void setMaxId(final long maxId) { + if (maxId < 1) throw new IllegalArgumentException("max_id should be positive integer. passed:" + maxId); + this.maxId = maxId; + } + + public void setPage(final int page) { + if (page < 1) throw new IllegalArgumentException("page should be positive integer. passed:" + page); + this.page = page; + } + + public void setSinceId(final long sinceId) { + if (sinceId < 1) throw new IllegalArgumentException("since_id should be positive integer. passed:" + sinceId); + this.sinceId = sinceId; + } + + public Paging sinceId(final long sinceId) { + setSinceId(sinceId); + return this; + } + + @Override + public String toString() { + return "Paging{" + "page=" + page + ", count=" + count + ", sinceId=" + sinceId + ", maxId=" + maxId + '}'; + } + + private void addPostParameter(final char[] supportedParams, final char paramKey, + final List pagingParams, final String paramName, final long paramValue) { + boolean supported = false; + for (final char supportedParam : supportedParams) { + if (supportedParam == paramKey) { + supported = true; + break; + } + } + if (!supported && -1 != paramValue) + throw new IllegalStateException("Paging parameter [" + paramName + + "] is not supported with this operation."); + if (-1 != paramValue) { + pagingParams.add(new HttpParameter(paramName, String.valueOf(paramValue))); + } + } + + /* package */HttpParameter[] asPostParameterArray() { + final List list = asPostParameterList(SMCP, COUNT); + if (list.size() == 0) return NULL_PARAMETER_ARRAY; + return list.toArray(new HttpParameter[list.size()]); + } + + /** + * Converts the pagination parameters into a List of PostParameter.
+ * This method also Validates the preset parameters, and throws + * IllegalStateException if any unsupported parameter is set. + * + * @param supportedParams char array representation of supported parameters + * @param perPageParamName name used for per-page parameter. + * getUserListStatuses() requires "per_page" instead of "count". + * @return list of PostParameter + */ + /* package */HttpParameter[] asPostParameterArray(final char[] supportedParams, final String perPageParamName) { + final List pagingParams = new ArrayList(supportedParams.length); + addPostParameter(supportedParams, 's', pagingParams, "since_id", getSinceId()); + addPostParameter(supportedParams, 'm', pagingParams, "max_id", getMaxId()); + addPostParameter(supportedParams, 'c', pagingParams, perPageParamName, getCount()); + addPostParameter(supportedParams, 'p', pagingParams, "page", getPage()); + if (pagingParams.size() == 0) + return NULL_PARAMETER_ARRAY; + else + return pagingParams.toArray(new HttpParameter[pagingParams.size()]); + } + + /* package */List asPostParameterList() { + return asPostParameterList(SMCP, COUNT); + } + + /* package */List asPostParameterList(final char[] supportedParams) { + return asPostParameterList(supportedParams, COUNT); + } + + /** + * Converts the pagination parameters into a List of PostParameter.
+ * This method also Validates the preset parameters, and throws + * IllegalStateException if any unsupported parameter is set. + * + * @param supportedParams char array representation of supported parameters + * @param perPageParamName name used for per-page parameter. + * getUserListStatuses() requires "per_page" instead of "count". + * @return list of PostParameter + */ + /* package */List asPostParameterList(final char[] supportedParams, final String perPageParamName) { + final List pagingParams = new ArrayList(supportedParams.length); + addPostParameter(supportedParams, 's', pagingParams, "since_id", getSinceId()); + addPostParameter(supportedParams, 'm', pagingParams, "max_id", getMaxId()); + addPostParameter(supportedParams, 'c', pagingParams, perPageParamName, getCount()); + addPostParameter(supportedParams, 'p', pagingParams, "page", getPage()); + if (pagingParams.size() == 0) + return NULL_PARAMETER_LIST; + else + return pagingParams; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Place.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Place.java new file mode 100644 index 00000000..e8fb1f67 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Place.java @@ -0,0 +1,33 @@ +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public interface Place extends TwitterResponse, Comparable { + GeoLocation[][] getBoundingBoxCoordinates(); + + String getBoundingBoxType(); + + Place[] getContainedWithIn(); + + String getCountry(); + + String getCountryCode(); + + String getFullName(); + + GeoLocation[][] getGeometryCoordinates(); + + String getGeometryType(); + + String getId(); + + String getName(); + + String getPlaceType(); + + String getStreetAddress(); + + String getURL(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Query.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Query.java new file mode 100644 index 00000000..8635b65a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Query.java @@ -0,0 +1,530 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import twitter4j.http.HttpParameter; + +/** + * A data class represents search query.
+ * An instance of this class is NOT thread safe.
+ * Instances can be shared across threads, but should not be mutated while a + * search is ongoing. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see GET search | + * Twitter Developers + * @see Twitter API / Search + * Operators + */ +public final class Query { + private String query = null; + private String lang = null; + private String locale = null; + private long maxId = -1l; + private int rpp = -1; + private int page = -1; + private String since = null; + private long sinceId = -1; + private String geocode = null; + private String until = null; + private String resultType = null; + + public static final String MILES = "mi"; + + public static final String KILOMETERS = "km"; + + /** + * mixed: Include both popular and real time results in the response. + * recent: return only the most recent results in the response popular: + * return only the most popular results in the response. + */ + public final static String MIXED = "mixed"; + + public final static String POPULAR = "popular"; + + public final static String RECENT = "recent"; + + private static HttpParameter WITH_TWITTER_USER_ID = new HttpParameter("with_twitter_user_id", "true"); + + public Query() { + } + + public Query(final String query) { + this.query = query; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Query query1 = (Query) o; + + if (maxId != query1.maxId) return false; + if (page != query1.page) return false; + if (rpp != query1.rpp) return false; + if (sinceId != query1.sinceId) return false; + if (geocode != null ? !geocode.equals(query1.geocode) : query1.geocode != null) return false; + if (lang != null ? !lang.equals(query1.lang) : query1.lang != null) return false; + if (locale != null ? !locale.equals(query1.locale) : query1.locale != null) return false; + if (query != null ? !query.equals(query1.query) : query1.query != null) return false; + if (since != null ? !since.equals(query1.since) : query1.since != null) return false; + if (until != null ? !until.equals(query1.until) : query1.until != null) return false; + if (resultType != null ? !resultType.equals(query1.resultType) : query1.resultType != null) return false; + + return true; + } + + /** + * returns tweets by users located within a given radius of the given + * latitude/longitude, where the user's location is taken from their Twitter + * profile + * + * @param location geo location + * @param radius radius + * @param unit Query.MILES or Query.KILOMETERS + * @return the instance + * @since Twitter4J 2.1.0 + */ + public Query geoCode(final GeoLocation location, final double radius, final String unit) { + setGeoCode(location, radius, unit); + return this; + } + + /** + * Returns the specified geocode + * + * @return geocode + */ + public String getGeocode() { + return geocode; + } + + /** + * Returns the lang + * + * @return lang + */ + public String getLang() { + return lang; + } + + /** + * Returns the language of the query you are sending (only ja is currently + * effective). This is intended for language-specific clients and the + * default should work in the majority of cases. + * + * @return locale + * @since Twitter4J 2.1.1 + */ + public String getLocale() { + return locale; + } + + /** + * Returns tweets with status ids less than the given id. + * + * @return maxId + * @since Twitter4J 2.1.1 + */ + public long getMaxId() { + return maxId; + } + + /** + * Returns the page number (starting at 1) to return, up to a max of roughly + * 1500 results + * + * @return the page number (starting at 1) to return + */ + public int getPage() { + return page; + } + + /** + * Returns the specified query + * + * @return query + */ + public String getQuery() { + return query; + } + + /** + * Returns resultType + * + * @return the resultType + * @since Twitter4J 2.1.3 + */ + public String getResultType() { + return resultType; + } + + /** + * Returns the number of tweets to return per page, up to a max of 100 + * + * @return rpp + */ + public int getRpp() { + return rpp; + } + + /** + * Returns tweets with since the given date. Date should be formatted as + * YYYY-MM-DD + * + * @return since + * @since Twitter4J 2.1.1 + */ + public String getSince() { + return since; + } + + /** + * returns sinceId + * + * @return sinceId + */ + public long getSinceId() { + return sinceId; + } + + /** + * Returns until + * + * @return until + * @since Twitter4J 2.1.1 + */ + public String getUntil() { + return until; + } + + @Override + public int hashCode() { + int result = query != null ? query.hashCode() : 0; + result = 31 * result + (lang != null ? lang.hashCode() : 0); + result = 31 * result + (locale != null ? locale.hashCode() : 0); + result = 31 * result + (int) (maxId ^ maxId >>> 32); + result = 31 * result + rpp; + result = 31 * result + page; + result = 31 * result + (since != null ? since.hashCode() : 0); + result = 31 * result + (int) (sinceId ^ sinceId >>> 32); + result = 31 * result + (geocode != null ? geocode.hashCode() : 0); + result = 31 * result + (until != null ? until.hashCode() : 0); + result = 31 * result + (resultType != null ? resultType.hashCode() : 0); + return result; + } + + /** + * restricts tweets to the given language, given by an ISO 639-1 code + * + * @param lang an ISO 639-1 + * code + * @return the instance + * @since Twitter4J 2.1.0 + */ + public Query lang(final String lang) { + setLang(lang); + return this; + } + + /** + * Specify the language of the query you are sending (only ja is currently + * effective). This is intended for language-specific clients and the + * default should work in the majority of cases. + * + * @param locale the locale + * @return the instance + * @since Twitter4J 2.1.1 + */ + public Query locale(final String locale) { + setLocale(locale); + return this; + } + + /** + * If specified, returns tweets with status ids less than the given id. + * + * @param maxId maxId + * @return this instance + * @since Twitter4J 2.1.1 + */ + public Query maxId(final long maxId) { + setMaxId(maxId); + return this; + } + + /** + * sets the page number (starting at 1) to return, up to a max of roughly + * 1500 results + * + * @param page the page number (starting at 1) to return + * @return the instance + * @since Twitter4J 2.1.0 + */ + public Query page(final int page) { + setPage(page); + return this; + } + + /** + * Sets the query string + * + * @param query the query string + * @return the instance + * @see GET search + * | Twitter Developers + * @see Twitter API / Search + * Operators + * @since Twitter4J 2.1.0 + */ + public Query query(final String query) { + setQuery(query); + return this; + } + + /** + * If specified, returns tweets included popular or real time or both in the + * responce + * + * @param resultType resultType + * @return the instance + * @since Twitter4J 2.1.3 + */ + public Query resultType(final String resultType) { + setResultType(resultType); + return this; + } + + /** + * sets the number of tweets to return per page, up to a max of 100 + * + * @param rpp the number of tweets to return per page + * @return the instance + * @since Twitter4J 2.1.0 + */ + public Query rpp(final int rpp) { + setRpp(rpp); + return this; + } + + /** + * returns tweets by users located within a given radius of the given + * latitude/longitude, where the user's location is taken from their Twitter + * profile + * + * @param location geo location + * @param radius radius + * @param unit Query.MILES or Query.KILOMETERS + */ + public void setGeoCode(final GeoLocation location, final double radius, final String unit) { + geocode = location.getLatitude() + "," + location.getLongitude() + "," + radius + unit; + } + + /** + * restricts tweets to the given language, given by an ISO 639-1 code + * + * @param lang an ISO 639-1 + * code + */ + public void setLang(final String lang) { + this.lang = lang; + } + + /** + * Specify the language of the query you are sending (only ja is currently + * effective). This is intended for language-specific clients and the + * default should work in the majority of cases. + * + * @param locale the locale + * @since Twitter4J 2.1.1 + */ + public void setLocale(final String locale) { + this.locale = locale; + } + + /** + * If specified, returns tweets with status ids less than the given id. + * + * @param maxId maxId + * @since Twitter4J 2.1.1 + */ + public void setMaxId(final long maxId) { + this.maxId = maxId; + } + + /** + * sets the page number (starting at 1) to return, up to a max of roughly + * 1500 results + * + * @param page the page number (starting at 1) to return + */ + public void setPage(final int page) { + this.page = page; + } + + /** + * Sets the query string + * + * @param query the query string + * @see GET search + * | Twitter Developers + * @see Twitter API / Search + * Operators + */ + public void setQuery(final String query) { + this.query = query; + } + + /** + * Default value is Query.MIXED if parameter not specified + * + * @param resultType Query.MIXED or Query.POPULAR or Query.RECENT + * @since Twitter4J 2.1.3 + */ + public void setResultType(final String resultType) { + this.resultType = resultType; + } + + /** + * sets the number of tweets to return per page, up to a max of 100 + * + * @param rpp the number of tweets to return per page + */ + public void setRpp(final int rpp) { + this.rpp = rpp; + } + + /** + * If specified, returns tweets with since the given date. Date should be + * formatted as YYYY-MM-DD + * + * @param since since + * @since Twitter4J 2.1.1 + */ + public void setSince(final String since) { + this.since = since; + } + + /** + * returns tweets with status ids greater than the given id. + * + * @param sinceId returns tweets with status ids greater than the given id + */ + public void setSinceId(final long sinceId) { + this.sinceId = sinceId; + } + + /** + * If specified, returns tweets with generated before the given date. Date + * should be formatted as YYYY-MM-DD + * + * @param until until + * @since Twitter4J 2.1.1 + */ + public void setUntil(final String until) { + this.until = until; + } + + /** + * If specified, returns tweets with since the given date. Date should be + * formatted as YYYY-MM-DD + * + * @param since since + * @return since + * @since Twitter4J 2.1.1 + */ + public Query since(final String since) { + setSince(since); + return this; + } + + /** + * returns tweets with status ids greater than the given id. + * + * @param sinceId returns tweets with status ids greater than the given id + * @return the instance + * @since Twitter4J 2.1.0 + */ + public Query sinceId(final long sinceId) { + setSinceId(sinceId); + return this; + } + + @Override + public String toString() { + return "Query{" + "query='" + query + '\'' + ", lang='" + lang + '\'' + ", locale='" + locale + '\'' + + ", maxId=" + maxId + ", rpp=" + rpp + ", page=" + page + ", since='" + since + '\'' + ", sinceId=" + + sinceId + ", geocode='" + geocode + '\'' + ", until='" + until + '\'' + ", resultType='" + resultType + + '\'' + '}'; + } + + /** + * If specified, returns tweets with generated before the given date. Date + * should be formatted as YYYY-MM-DD + * + * @param until until + * @return the instance + * @since Twitter4J 2.1.1 + */ + public Query until(final String until) { + setUntil(until); + return this; + } + + private void appendParameter(final String name, final long value, final List params) { + if (0 <= value) { + params.add(new HttpParameter(name, String.valueOf(value))); + } + } + + private void appendParameter(final String name, final String value, final List params) { + if (value != null) { + params.add(new HttpParameter(name, value)); + } + } + + /* package */HttpParameter[] asHttpParameterArray(final HttpParameter... extraParams) { + final ArrayList params = new ArrayList(); + appendParameter("q", query, params); + appendParameter("lang", lang, params); + appendParameter("locale", locale, params); + appendParameter("max_id", maxId, params); + appendParameter("rpp", rpp, params); + appendParameter("page", page, params); + appendParameter("since", since, params); + appendParameter("since_id", sinceId, params); + appendParameter("geocode", geocode, params); + appendParameter("until", until, params); + appendParameter("result_type", resultType, params); + params.add(WITH_TWITTER_USER_ID); + if (extraParams != null) { + Collections.addAll(params, extraParams); + } + final HttpParameter[] paramArray = new HttpParameter[params.size()]; + return params.toArray(paramArray); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/QueryResult.java b/firetweet.component.twitter4j/src/main/java/twitter4j/QueryResult.java new file mode 100644 index 00000000..2b1fdc25 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/QueryResult.java @@ -0,0 +1,40 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * A data interface representing search API response + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface QueryResult extends ResponseList { + double getCompletedIn(); + + long getMaxId(); + + int getPage(); + + String getQuery(); + + String getRefreshUrl(); + + int getResultsPerPage(); + + long getSinceId(); + + String getWarning(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatus.java b/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatus.java new file mode 100644 index 00000000..2d84c55b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatus.java @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * A data interface representing Twitter REST API's rate limit status + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see Rate Limiting | + * Twitter Developers + */ +public interface RateLimitStatus { + + int getLimit(); + + int getRemaining(); + + /** + * Returns the remaining number of API requests available.
+ * This value is identical to the "X-RateLimit-Remaining" response + * header. + * + * @return the remaining number of API requests available + */ + int getRemainingHits(); + + /** + * Returns the seconds the current rate limiting period ends.
+ * This should be a same as getResetTime().getTime()/1000. + * + * @return the seconds the current rate limiting period ends + * @since Twitter4J 2.0.9 + */ + int getResetTimeInSeconds(); + + /** + * Returns the amount of seconds until the current rate limiting period + * ends.
+ * This is a value provided/calculated only by Twitter4J for handiness and + * not a part of the twitter API spec. + * + * @return the amount of seconds until next rate limiting period + * @since Twitter4J 2.1.0 + */ + int getSecondsUntilReset(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatusEvent.java b/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatusEvent.java new file mode 100644 index 00000000..cc1be404 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatusEvent.java @@ -0,0 +1,55 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.util.EventObject; + +/** + * A data interface representing Twitter REST API's rate limit status + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see Rate Limiting | + * Twitter Developers + */ +public final class RateLimitStatusEvent extends EventObject { + + private static final long serialVersionUID = 3749366911109722414L; + + private final RateLimitStatus rateLimitStatus; + + private final boolean isAccountRateLimitStatus; + + RateLimitStatusEvent(final Object source, final RateLimitStatus rateLimitStatus, + final boolean isAccountRateLimitStatus) { + super(source); + this.rateLimitStatus = rateLimitStatus; + this.isAccountRateLimitStatus = isAccountRateLimitStatus; + } + + public RateLimitStatus getRateLimitStatus() { + return rateLimitStatus; + } + + public boolean isAccountRateLimitStatus() { + return isAccountRateLimitStatus; + } + + public boolean isIPRateLimitStatus() { + return !isAccountRateLimitStatus; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatusListener.java b/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatusListener.java new file mode 100644 index 00000000..d7928301 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/RateLimitStatusListener.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Andrew Hedges - andrew.hedges at gmail.com + */ +public interface RateLimitStatusListener { + + /** + * Called when the account or IP address is hitting the rate limit.
+ * onRateLimitStatus will be also called before this event. + * + * @param event rate limit status event. + */ + public void onRateLimitReached(RateLimitStatusEvent event); + + /** + * Called when the response contains rate limit status. + * + * @param event rate limit status event. + */ + public void onRateLimitStatus(RateLimitStatusEvent event); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Relationship.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Relationship.java new file mode 100644 index 00000000..22e50da4 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Relationship.java @@ -0,0 +1,112 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * A data interface that has detailed information about a relationship between + * two users + * + * @author Perry Sakkaris - psakkaris at gmail.com + * @see GET + * friendships/show | Twitter Developers + * @since Twitter4J 2.1.0 + */ +public interface Relationship extends TwitterResponse { + boolean canSourceDMTarget(); + + boolean canSourceMediaTagTarget(); + + /** + * Returns the source user id + * + * @return the source user id + */ + long getSourceUserId(); + + /** + * Returns the source user screen name + * + * @return returns the source user screen name + */ + String getSourceUserScreenName(); + + /** + * Returns the target user id + * + * @return target user id + */ + long getTargetUserId(); + + /** + * Returns the target user screen name + * + * @return the target user screen name + */ + String getTargetUserScreenName(); + + /** + * Returns if the source user is blocking the target user + * + * @return if the source is blocking the target + */ + boolean isSourceBlockingTarget(); + + boolean isSourceBlockedByTarget(); + + /** + * Checks if source user is being followed by target user + * + * @return true if source user is being followed by target user + */ + boolean isSourceFollowedByTarget(); + + /** + * Checks if source user is following target user + * + * @return true if source user is following target user + */ + boolean isSourceFollowingTarget(); + + boolean isSourceMarkedTargetAsSpam(); + + boolean isSourceMutingTarget(); + + /** + * Checks if the source user has enabled notifications for updates of the + * target user + * + * @return true if source user enabled notifications for target user + */ + boolean isSourceNotificationsEnabled(); + + /** + * Checks if target user is being followed by source user.
+ * This method is equivalent to isSourceFollowingTarget(). + * + * @return true if target user is being followed by source user + */ + boolean isTargetFollowedBySource(); + + /** + * Checks if target user is following source user.
+ * This method is equivalent to isSourceFollowedByTarget(). + * + * @return true if target user is following source user + */ + boolean isTargetFollowingSource(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/ReportAs.java b/firetweet.component.twitter4j/src/main/java/twitter4j/ReportAs.java new file mode 100644 index 00000000..43ddce5a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/ReportAs.java @@ -0,0 +1,23 @@ +package twitter4j; + +public enum ReportAs { + ABUSE("abuse"), COMPROMISED("compromised"), SPAM("spam"); + + private String type; + + ReportAs(final String type) { + this.type = type; + } + + public String value() { + return type; + } + + public static ReportAs parse(final String string) { + try { + return ReportAs.valueOf(string.toUpperCase()); + } catch (final Exception e) { + return SPAM; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/ResponseList.java b/firetweet.component.twitter4j/src/main/java/twitter4j/ResponseList.java new file mode 100644 index 00000000..fb796ff3 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/ResponseList.java @@ -0,0 +1,35 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.List; + +/** + * List of TwitterResponse. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface ResponseList extends TwitterResponse, List, Serializable { + + /** + * {@inheritDoc} + */ + @Override + public RateLimitStatus getRateLimitStatus(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/SavedSearch.java b/firetweet.component.twitter4j/src/main/java/twitter4j/SavedSearch.java new file mode 100644 index 00000000..3bcca440 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/SavedSearch.java @@ -0,0 +1,39 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.Date; + +/** + * A data interface representing a Saved Search + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.8 + */ +public interface SavedSearch extends Comparable, TwitterResponse, Serializable { + Date getCreatedAt(); + + int getId(); + + String getName(); + + int getPosition(); + + String getQuery(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/SettingsUpdate.java b/firetweet.component.twitter4j/src/main/java/twitter4j/SettingsUpdate.java new file mode 100644 index 00000000..d45a307d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/SettingsUpdate.java @@ -0,0 +1,84 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; + +import twitter4j.http.HttpParameter; + +/** + * Created by mariotaku on 15/1/6. + */ +public class SettingsUpdate implements Serializable { + + private final HashMap settingsMap = new HashMap<>(); + + public void set(String key, boolean value) { + settingsMap.put(key, new HttpParameter(key, value)); + } + + public void set(String key, int value) { + settingsMap.put(key, new HttpParameter(key, value)); + } + + public void set(String key, String value) { + settingsMap.put(key, new HttpParameter(key, value)); + } + + public void setTrendLocationWoeid(int woeid) { + set("trend_location_woeid", woeid); + } + + public void setSleepTimeEnabled(boolean enabled) { + set("sleep_time_enabled", enabled); + } + + public void setStartSleepTime(int startSleepTime) { + set("start_sleep_time", startSleepTime); + } + + public void setEndSleepTime(int endSleepTime) { + set("end_sleep_time", endSleepTime); + } + + public void setTimezone(String timezone) { + set("time_zone", timezone); + } + + public void setProtected(boolean userProtected) { + set("protected", userProtected); + } + + public void setLang(String lang) { + set("lang", lang); + } + + public void setScreenName(String screenName) { + set("screen_name", screenName); + } + + + void addToHttpParameterList(List parameterList) { + parameterList.addAll(settingsMap.values()); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/SimilarPlaces.java b/firetweet.component.twitter4j/src/main/java/twitter4j/SimilarPlaces.java new file mode 100644 index 00000000..2557cc9e --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/SimilarPlaces.java @@ -0,0 +1,35 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.7 + */ +public interface SimilarPlaces extends ResponseList, Serializable { + /** + * Returns the token needed to be able to create a new place with + * {@link twitter4j.api.PlacesGeoResources#createPlace(String, String, String, GeoLocation, String)} + * . + * + * @return token the token needed to be able to create a new place with + * {@link twitter4j.api.PlacesGeoResources#createPlace(String, String, String, GeoLocation, String)} + */ + String getToken(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Status.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Status.java new file mode 100644 index 00000000..55bc4d79 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Status.java @@ -0,0 +1,177 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.Date; + +/** + * A data interface representing one single status of a user. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface Status extends Comparable, TwitterResponse, ExtendedEntitySupport, Serializable { + + /** + * Returns an array of contributors, or null if no contributor is associated + * with this status. + * + * @since Twitter4J 2.2.3 + */ + long[] getContributors(); + + long getReplyCount(); + + long getDescendentReplyCount(); + + /** + * returns the created_at + * + * @return the created_at + */ + Date getCreatedAt(); + + long getCurrentUserRetweet(); + + long getFavoriteCount(); + + /** + * Returns The location that this tweet refers to if available. + * + * @return returns The location that this tweet refers to if available (can + * be null) + */ + GeoLocation getGeoLocation(); + + /** + * returns the status id of the tweet + * + * @return the status id + */ + long getId(); + + /** + * Returns the in_reply_to_screen_name + * + * @return the in_in_reply_to_screen_name + * @since Twitter4J 2.0.4 + */ + String getInReplyToScreenName(); + + /** + * Returns the in_reply_tostatus_id + * + * @return the in_reply_tostatus_id + */ + long getInReplyToStatusId(); + + /** + * Returns the in_reply_user_id + * + * @return the in_reply_tostatus_id + * @since Twitter4J 1.0.4 + */ + long getInReplyToUserId(); + + /** + * Returns the place associated with the Tweet. + * + * @return The place associated with the Tweet + */ + Place getPlace(); + + /** + * returns the raw text + * + * @return the raw text + */ + String getRawText(); + + /** + * Returns the number of times this tweet has been retweeted, or -1 when the + * tweet was created before this feature was enabled. + * + * @return the retweet count. + */ + long getRetweetCount(); + + /** + * @since Twitter4J 2.1.0 + */ + Status getRetweetedStatus(); + + Status getQuotedStatus(); + + /** + * returns the source of the tweet + * + * @return the source of the tweet + */ + String getSource(); + + /** + * returns the text + * + * @return the text + */ + String getText(); + + /** + * Return the user associated with the status.
+ * This can be null if the instance if from User.getStatus(). + * + * @return the user + */ + User getUser(); + + /** + * Test if the status is favorited + * + * @return true if favorited + * @since Twitter4J 1.0.4 + */ + boolean isFavorited(); + + boolean isPossiblySensitive(); + + /** + * @since Twitter4J 2.0.10 + */ + boolean isRetweet(); + + boolean isQuote(); + + /** + * Returns true if the authenticating user has retweeted this tweet, or + * false when the tweet was created before this feature was enabled. + * + * @return whether the authenticating user has retweeted this tweet. + * @since Twitter4J 2.1.4 + */ + boolean isRetweetedByMe(); + + /** + * Test if the status is truncated + * + * @return true if truncated + * @since Twitter4J 1.0.4 + */ + boolean isTruncated(); + + CardEntity getCard(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/StatusActivitySummary.java b/firetweet.component.twitter4j/src/main/java/twitter4j/StatusActivitySummary.java new file mode 100644 index 00000000..41a4510f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/StatusActivitySummary.java @@ -0,0 +1,19 @@ +package twitter4j; + +public interface StatusActivitySummary extends TwitterResponse { + + public long getDescendentReplyCount(); + + public IDs getFavoriters(); + + public long getFavoritersCount(); + + public IDs getRepliers(); + + public long getRepliersCount(); + + public IDs getRetweeters(); + + public long getRetweetersCount(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/StatusUpdate.java b/firetweet.component.twitter4j/src/main/java/twitter4j/StatusUpdate.java new file mode 100644 index 00000000..045fd32b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/StatusUpdate.java @@ -0,0 +1,220 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import twitter4j.http.HttpParameter; +import twitter4j.internal.util.InternalStringUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public final class StatusUpdate implements Serializable { + + private static final long serialVersionUID = -2522880289943829826L; + private final String status; + private long inReplyToStatusId = -1l; + private GeoLocation location = null; + private String placeId = null; + private boolean displayCoordinates = true; + private boolean possiblySensitive; + private long[] mediaIds; + + public StatusUpdate(final String status) { + this.status = status; + } + + public StatusUpdate displayCoordinates(final boolean displayCoordinates) { + setDisplayCoordinates(displayCoordinates); + return this; + } + + public long getInReplyToStatusId() { + return inReplyToStatusId; + } + + public GeoLocation getLocation() { + return location; + } + + public long[] getMediaIds() { + return mediaIds; + } + + public String getPlaceId() { + return placeId; + } + + public String getStatus() { + return status; + } + + public StatusUpdate inReplyToStatusId(final long inReplyToStatusId) { + setInReplyToStatusId(inReplyToStatusId); + return this; + } + + public boolean isDisplayCoordinates() { + return displayCoordinates; + } + + /** + * @since Twitter4J 2.2.5 + */ + public boolean isPossiblySensitive() { + return possiblySensitive; + } + + public StatusUpdate location(final GeoLocation location) { + setLocation(location); + return this; + } + + public StatusUpdate mediaIds(final long... mediaIds) { + setMediaIds(mediaIds); + return this; + } + + public StatusUpdate placeId(final String placeId) { + setPlaceId(placeId); + return this; + } + + /** + * @since Twitter4J 2.2.5 + */ + public StatusUpdate possiblySensitive(final boolean possiblySensitive) { + setPossiblySensitive(possiblySensitive); + return this; + } + + public void setDisplayCoordinates(final boolean displayCoordinates) { + this.displayCoordinates = displayCoordinates; + } + + public void setInReplyToStatusId(final long inReplyToStatusId) { + this.inReplyToStatusId = inReplyToStatusId; + } + + public void setLocation(final GeoLocation location) { + this.location = location; + } + + + public void setMediaIds(final long... mediaIds) { + this.mediaIds = mediaIds; + } + + public void setPlaceId(final String placeId) { + this.placeId = placeId; + } + + /** + * @since Twitter4J 2.2.5 + */ + public void setPossiblySensitive(final boolean possiblySensitive) { + this.possiblySensitive = possiblySensitive; + } + + private void appendParameter(final String name, final double value, final List params) { + params.add(new HttpParameter(name, String.valueOf(value))); + } + + private void appendParameter(final String name, final long value, final List params) { + params.add(new HttpParameter(name, String.valueOf(value))); + } + + private void appendParameter(final String name, final String value, final List params) { + if (value != null) { + params.add(new HttpParameter(name, value)); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StatusUpdate that = (StatusUpdate) o; + + if (displayCoordinates != that.displayCoordinates) return false; + if (inReplyToStatusId != that.inReplyToStatusId) return false; + if (possiblySensitive != that.possiblySensitive) return false; + if (location != null ? !location.equals(that.location) : that.location != null) + return false; + if (!Arrays.equals(mediaIds, that.mediaIds)) return false; + if (placeId != null ? !placeId.equals(that.placeId) : that.placeId != null) return false; + if (status != null ? !status.equals(that.status) : that.status != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = status != null ? status.hashCode() : 0; + result = 31 * result + (int) (inReplyToStatusId ^ (inReplyToStatusId >>> 32)); + result = 31 * result + (location != null ? location.hashCode() : 0); + result = 31 * result + (placeId != null ? placeId.hashCode() : 0); + result = 31 * result + (displayCoordinates ? 1 : 0); + result = 31 * result + (possiblySensitive ? 1 : 0); + result = 31 * result + (mediaIds != null ? Arrays.hashCode(mediaIds) : 0); + return result; + } + + @Override + public String toString() { + return "StatusUpdate{" + + "status='" + status + '\'' + + ", inReplyToStatusId=" + inReplyToStatusId + + ", location=" + location + + ", placeId='" + placeId + '\'' + + ", displayCoordinates=" + displayCoordinates + + ", possiblySensitive=" + possiblySensitive + + ", mediaIds=" + Arrays.toString(mediaIds) + + '}'; + } + + /* package */HttpParameter[] asHttpParameterArray(final HttpParameter includeEntities) { + final ArrayList params = new ArrayList(); + appendParameter("status", status, params); + if (-1 != inReplyToStatusId) { + appendParameter("in_reply_to_status_id", inReplyToStatusId, params); + } + if (location != null) { + appendParameter("lat", location.getLatitude(), params); + appendParameter("long", location.getLongitude(), params); + } + appendParameter("place_id", placeId, params); + if (!displayCoordinates) { + appendParameter("display_coordinates", "false", params); + } + params.add(includeEntities); + if (mediaIds != null) { + params.add(new HttpParameter("media_ids", InternalStringUtil.join(mediaIds))); + } + + final HttpParameter[] paramArray = new HttpParameter[params.size()]; + return params.toArray(paramArray); + } + + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TimeZone.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TimeZone.java new file mode 100644 index 00000000..763c1678 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TimeZone.java @@ -0,0 +1,30 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * @author Alessandro Bahgat - ale.bahgat at gmail.com + */ +public interface TimeZone extends Serializable { + String getName(); + + String tzinfoName(); + + int utcOffset(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TranslationResult.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TranslationResult.java new file mode 100644 index 00000000..1a858acd --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TranslationResult.java @@ -0,0 +1,15 @@ +package twitter4j; + +public interface TranslationResult extends TwitterResponse { + + public long getId(); + + public String getLang(); + + public String getText(); + + public String getTranslatedLang(); + + public String getTranslationType(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Trend.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Trend.java new file mode 100644 index 00000000..1cf2f5d8 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Trend.java @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * A data interface representing Trend. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.2 + */ +public interface Trend extends Serializable { + String getName(); + + String getQuery(); + + String getUrl(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Trends.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Trends.java new file mode 100644 index 00000000..2f8e3e19 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Trends.java @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.Date; + +/** + * A data class representing Trends. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.2 + */ + +public interface Trends extends TwitterResponse, Comparable, Serializable { + Date getAsOf(); + + /** + * Returns the location associated with the trends.
+ * This method is effective only with getLocalTrends() method.
+ * i.e. The return value of this method will be null with Search API Methods + * (getTrends(), getCurrentTrends(), getDailyTrends(), and + * getWeeklyTrends()).
+ * + * @return location + * @since Twitter4J 2.1.1 + */ + Location getLocation(); + + Date getTrendAt(); + + Trend[] getTrends(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Twitter.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Twitter.java new file mode 100644 index 00000000..247fd57a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Twitter.java @@ -0,0 +1,49 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import twitter4j.api.DirectMessagesResources; +import twitter4j.api.FavoritesResources; +import twitter4j.api.FriendsFollowersResources; +import twitter4j.api.HelpResources; +import twitter4j.api.ListsResources; +import twitter4j.api.MediaResources; +import twitter4j.api.PlacesGeoResources; +import twitter4j.api.PrivateActivityResources; +import twitter4j.api.PrivateDirectMessagesResources; +import twitter4j.api.PrivateFriendsFollowersResources; +import twitter4j.api.PrivateTimelinesResources; +import twitter4j.api.PrivateTweetResources; +import twitter4j.api.SavedSearchesResources; +import twitter4j.api.SearchResource; +import twitter4j.api.SpamReportingResources; +import twitter4j.api.TimelinesResources; +import twitter4j.api.TrendsResources; +import twitter4j.api.TweetResources; +import twitter4j.api.UsersResources; +import twitter4j.auth.OAuthSupport; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.0 + */ +public interface Twitter extends OAuthSupport, TwitterConstants, TwitterBase, SearchResource, TimelinesResources, + TweetResources, UsersResources, ListsResources, DirectMessagesResources, FriendsFollowersResources, + FavoritesResources, SpamReportingResources, SavedSearchesResources, TrendsResources, PlacesGeoResources, + HelpResources, PrivateActivityResources, PrivateTweetResources, PrivateTimelinesResources, + PrivateFriendsFollowersResources, PrivateDirectMessagesResources, MediaResources { +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterAPIConfiguration.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterAPIConfiguration.java new file mode 100644 index 00000000..0c59273f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterAPIConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.3 + */ +public interface TwitterAPIConfiguration extends TwitterResponse, Serializable { + int getCharactersReservedPerMedia(); + + int getMaxMediaPerUpload(); + + String[] getNonUsernamePaths(); + + int getPhotoSizeLimit(); + + Map getPhotoSizes(); + + int getShortURLLength(); + + int getShortURLLengthHttps(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterAPIMonitor.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterAPIMonitor.java new file mode 100644 index 00000000..1dc53805 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterAPIMonitor.java @@ -0,0 +1,71 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import twitter4j.management.APIStatistics; +import twitter4j.management.APIStatisticsMBean; + +/** + * Singleton instance of all Twitter API monitoring. Handles URL parsing and + * "wire off" logic. We could avoid using a singleton here if Twitter objects + * were instantiated from a factory. + * + * @author Nick Dellamaggiore (nick.dellamaggiore gmail.com) + * @since Twitter4J 2.2.1 + */ +public class TwitterAPIMonitor { + // https?:\/\/[^\/]+\/([a-zA-Z_\.]*).* + // finds the "method" part a Twitter REST API url, ignoring member-specific + // resource names + private static final Pattern pattern = Pattern.compile("https?:\\/\\/[^\\/]+\\/([a-zA-Z_\\.]*).*"); + + private static final TwitterAPIMonitor SINGLETON = new TwitterAPIMonitor(); + + private final APIStatistics STATISTICS = new APIStatistics(100); + + static { + System.setProperty("http.keepAlive", "false"); + } + + /** + * Constructor + */ + private TwitterAPIMonitor() { + } + + public APIStatisticsMBean getStatistics() { + return STATISTICS; + } + + void methodCalled(final String twitterUrl, final long elapsedTime, final boolean success) { + final Matcher matcher = pattern.matcher(twitterUrl); + if (matcher.matches() && matcher.groupCount() > 0) { + final String method = matcher.group(); + STATISTICS.methodCalled(method, elapsedTime, success); + } + } + + public static TwitterAPIMonitor getInstance() { + return SINGLETON; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterBase.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterBase.java new file mode 100644 index 00000000..91d46b68 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterBase.java @@ -0,0 +1,95 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import twitter4j.auth.Authorization; +import twitter4j.conf.Configuration; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.0 + */ +public interface TwitterBase { + + /** + * Registers a RateLimitStatusListener for account associated rate limits + * + * @param listener the listener to be added + * @see Rate Limiting | + * Twitter Developers + * @since Twitter4J 2.1.12 + */ + void addRateLimitStatusListener(RateLimitStatusListener listener); + + /** + * Returns the authorization scheme for this instance.
+ * The returned type will be either of BasicAuthorization, + * OAuthAuthorization, or NullAuthorization + * + * @return the authorization scheme for this instance + */ + Authorization getAuthorization(); + + /** + * Returns the configuration associated with this instance + * + * @return configuration associated with this instance + * @since Twitter4J 2.1.8 + */ + Configuration getConfiguration(); + + /** + * Returns authenticating user's user id.
+ * This method may internally call verifyCredentials() on the first + * invocation if
+ * - this instance is authenticated by Basic and email address is supplied + * instead of screen name, or - this instance is authenticated by OAuth.
+ * + * @return the authenticating user's id + * @throws twitter4j.TwitterException when verifyCredentials threw an exception. + * @throws IllegalStateException if no credentials are supplied. i.e.) this + * is an anonymous Twitter instance + * @since Twitter4J 2.1.1 + */ + long getId() throws TwitterException, IllegalStateException; + + /** + * Returns authenticating user's screen name.
+ * This method may internally call verifyCredentials() on the first + * invocation if
+ * - this instance is authenticated by Basic and email address is supplied + * instead of screen name, or - this instance is authenticated by OAuth.
+ * Note that this method returns a transiently cached (will be lost upon + * serialization) screen name while it is possible to change a user's screen + * name.
+ * + * @return the authenticating screen name + * @throws twitter4j.TwitterException when verifyCredentials threw an exception. + * @throws IllegalStateException if no credentials are supplied. i.e.) this + * is an anonymous Twitter instance + * @since Twitter4J 2.1.1 + */ + String getScreenName() throws TwitterException, IllegalStateException; + + /** + * Shuts down this instance and releases allocated resources. + */ + void shutdown(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterBaseImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterBaseImpl.java new file mode 100644 index 00000000..97e75e54 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterBaseImpl.java @@ -0,0 +1,531 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import twitter4j.auth.AccessToken; +import twitter4j.auth.Authorization; +import twitter4j.auth.AuthorizationFactory; +import twitter4j.auth.BasicAuthorization; +import twitter4j.auth.NullAuthorization; +import twitter4j.auth.OAuthAuthorization; +import twitter4j.auth.OAuthSupport; +import twitter4j.auth.RequestToken; +import twitter4j.auth.XAuthAuthorization; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpClientWrapper; +import twitter4j.http.HttpParameter; +import twitter4j.http.HttpResponse; +import twitter4j.http.HttpResponseEvent; +import twitter4j.http.HttpResponseListener; +import twitter4j.internal.json.InternalJSONFactory; +import twitter4j.internal.json.InternalJSONFactoryImpl; + +import static twitter4j.http.HttpResponseCode.ENHANCE_YOUR_CLAIM; +import static twitter4j.http.HttpResponseCode.SERVICE_UNAVAILABLE; + +/** + * Base class of Twitter / AsyncTwitter / TwitterStream supports OAuth. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +abstract class TwitterBaseImpl implements OAuthSupport, HttpResponseListener, TwitterConstants { + protected Configuration conf; + protected transient String screenName = null; + protected transient long id = 0; + + protected transient HttpClientWrapper http; + private List rateLimitStatusListeners = new ArrayList(0); + + protected InternalJSONFactory factory; + + protected Authorization auth; + + /* package */TwitterBaseImpl(final Configuration conf, final Authorization auth) { + this.conf = conf; + this.auth = auth; + init(); + } + + /** + * {@inheritDoc} + */ + public void addRateLimitStatusListener(final RateLimitStatusListener listener) { + rateLimitStatusListeners.add(listener); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof TwitterBaseImpl)) return false; + + final TwitterBaseImpl that = (TwitterBaseImpl) o; + + if (auth != null ? !auth.equals(that.auth) : that.auth != null) return false; + if (!conf.equals(that.conf)) return false; + if (http != null ? !http.equals(that.http) : that.http != null) return false; + if (!rateLimitStatusListeners.equals(that.rateLimitStatusListeners)) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + public final Authorization getAuthorization() { + return auth; + } + + /** + * {@inheritDoc} + */ + public Configuration getConfiguration() { + return conf; + } + + /** + * {@inheritDoc} + */ + public long getId() throws TwitterException, IllegalStateException { + if (!auth.isEnabled()) + throw new IllegalStateException( + "Neither user ID/password combination nor OAuth consumer key/secret combination supplied"); + if (0 == id) { + fillInIDAndScreenName(); + } + // retrieve the screen name if this instance is authenticated with OAuth + // or email address + return id; + } + + /** + * {@inheritDoc} Basic authenticated instance of this class will try + * acquiring an AccessToken using xAuth.
+ * In order to get access acquire AccessToken using xAuth, you must apply by + * sending an email to api@twitter.com + * all other applications will receive an HTTP 401 error. Web-based + * applications will not be granted access, except on a temporary basis for + * when they are converting from basic-authentication support to full OAuth + * support.
+ * Storage of Twitter usernames and passwords is forbidden. By using xAuth, + * you are required to store only access tokens and access token secrets. If + * the access token expires or is expunged by a user, you must ask for their + * login and password again before exchanging the credentials for an access + * token. + * + * @throws twitter4j.TwitterException When Twitter service or network is unavailable, + * when the user has not authorized, or when the client + * application is not permitted to use xAuth + * @see xAuth | Twitter + * Developers + */ + @Override + public synchronized AccessToken getOAuthAccessToken() throws TwitterException { + Authorization auth = getAuthorization(); + AccessToken oauthAccessToken; + if (auth instanceof BasicAuthorization) { + final BasicAuthorization basicAuth = (BasicAuthorization) auth; + auth = AuthorizationFactory.getInstance(conf); + if (auth instanceof OAuthAuthorization) { + this.auth = auth; + final OAuthAuthorization oauthAuth = (OAuthAuthorization) auth; + oauthAccessToken = oauthAuth.getOAuthAccessToken(basicAuth.getUserId(), basicAuth.getPassword()); + } else + throw new IllegalStateException("consumer key / secret combination not supplied."); + } else { + if (auth instanceof XAuthAuthorization) { + final XAuthAuthorization xauth = (XAuthAuthorization) auth; + this.auth = xauth; + final OAuthAuthorization oauthAuth = new OAuthAuthorization(conf); + oauthAuth.setOAuthConsumer(xauth.getConsumerKey(), xauth.getConsumerSecret()); + oauthAccessToken = oauthAuth.getOAuthAccessToken(xauth.getUserId(), xauth.getPassword()); + } else { + oauthAccessToken = getOAuth().getOAuthAccessToken(); + } + } + screenName = oauthAccessToken.getScreenName(); + id = oauthAccessToken.getUserId(); + return oauthAccessToken; + } + + /** + * {@inheritDoc} + * + * @throws IllegalStateException when AccessToken has already been retrieved + * or set + */ + @Override + public synchronized AccessToken getOAuthAccessToken(final RequestToken requestToken) throws TwitterException { + final OAuthSupport oauth = getOAuth(); + final AccessToken oauthAccessToken = oauth.getOAuthAccessToken(requestToken); + screenName = oauthAccessToken.getScreenName(); + return oauthAccessToken; + } + + /** + * {@inheritDoc} + * + * @throws IllegalStateException when AccessToken has already been retrieved + * or set + */ + @Override + public synchronized AccessToken getOAuthAccessToken(final RequestToken requestToken, final String oauthVerifier) + throws TwitterException { + return getOAuth().getOAuthAccessToken(requestToken, oauthVerifier); + } + + /** + * {@inheritDoc} + * + * @throws IllegalStateException when AccessToken has already been retrieved + * or set + */ + @Override + public synchronized AccessToken getOAuthAccessToken(final String oauthVerifier) throws TwitterException { + final AccessToken oauthAccessToken = getOAuth().getOAuthAccessToken(oauthVerifier); + screenName = oauthAccessToken.getScreenName(); + return oauthAccessToken; + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized AccessToken getOAuthAccessToken(final String screenName, final String password) + throws TwitterException { + return getOAuth().getOAuthAccessToken(screenName, password); + } + + /* OAuth support methods */ + + /** + * {@inheritDoc} + */ + @Override + public RequestToken getOAuthRequestToken() throws TwitterException { + return getOAuthRequestToken(null); + } + + /** + * {@inheritDoc} + */ + @Override + public RequestToken getOAuthRequestToken(final String callbackUrl) throws TwitterException { + return getOAuth().getOAuthRequestToken(callbackUrl); + } + + /** + * {@inheritDoc} + */ + @Override + public RequestToken getOAuthRequestToken(final String callbackUrl, final String xAuthAccessType) + throws TwitterException { + return getOAuth().getOAuthRequestToken(callbackUrl, xAuthAccessType); + } + + /** + * {@inheritDoc} + */ + public String getScreenName() throws TwitterException, IllegalStateException { + if (!auth.isEnabled()) + throw new IllegalStateException( + "Neither user ID/password combination nor OAuth consumer key/secret combination supplied"); + if (null == screenName) { + if (auth instanceof BasicAuthorization) { + screenName = ((BasicAuthorization) auth).getUserId(); + if (-1 != screenName.indexOf("@")) { + screenName = null; + } + } + if (null == screenName) { + // retrieve the screen name if this instance is authenticated + // with OAuth or email address + fillInIDAndScreenName(); + } + } + return screenName; + } + + // methods declared in OAuthSupport interface + + @Override + public int hashCode() { + int result = conf.hashCode(); + result = 31 * result + (http != null ? http.hashCode() : 0); + result = 31 * result + rateLimitStatusListeners.hashCode(); + result = 31 * result + (auth != null ? auth.hashCode() : 0); + return result; + } + + @Override + public void httpResponseReceived(final HttpResponseEvent event) { + if (rateLimitStatusListeners.size() != 0) { + final HttpResponse res = event.getResponse(); + final TwitterException te = event.getTwitterException(); + RateLimitStatus rateLimitStatus; + int statusCode; + if (te != null) { + rateLimitStatus = te.getRateLimitStatus(); + statusCode = te.getStatusCode(); + } else { + rateLimitStatus = InternalJSONFactoryImpl.createRateLimitStatusFromResponseHeader(res); + statusCode = res.getStatusCode(); + } + if (rateLimitStatus != null) { + final RateLimitStatusEvent statusEvent = new RateLimitStatusEvent(this, rateLimitStatus, + event.isAuthenticated()); + if (statusCode == ENHANCE_YOUR_CLAIM || statusCode == SERVICE_UNAVAILABLE) { + // EXCEEDED_RATE_LIMIT_QUOTA is returned by Rest API + // SERVICE_UNAVAILABLE is returned by Search API + for (final RateLimitStatusListener listener : rateLimitStatusListeners) { + listener.onRateLimitStatus(statusEvent); + listener.onRateLimitReached(statusEvent); + } + } else { + for (final RateLimitStatusListener listener : rateLimitStatusListeners) { + listener.onRateLimitStatus(statusEvent); + } + } + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void setOAuthAccessToken(final AccessToken accessToken) { + getOAuth().setOAuthAccessToken(accessToken); + } + + /** + * {@inheritDoc} + */ + @Override + public synchronized void setOAuthConsumer(final String consumerKey, final String consumerSecret) { + if (null == consumerKey) throw new NullPointerException("consumer key is null"); + if (null == consumerSecret) throw new NullPointerException("consumer secret is null"); + if (auth instanceof NullAuthorization) { + final OAuthAuthorization oauth = new OAuthAuthorization(conf); + oauth.setOAuthConsumer(consumerKey, consumerSecret); + auth = oauth; + } else if (auth instanceof BasicAuthorization) { + final XAuthAuthorization xauth = new XAuthAuthorization((BasicAuthorization) auth); + xauth.setOAuthConsumer(consumerKey, consumerSecret); + auth = xauth; + } else if (auth instanceof OAuthAuthorization) + throw new IllegalStateException("consumer key/secret pair already set."); + } + + /** + * {@inheritDoc} + */ + public void shutdown() { + if (http != null) { + http.shutdown(); + } + } + + @Override + public String toString() { + return "TwitterBase{" + "conf=" + conf + ", http=" + http + ", rateLimitStatusListeners=" + + rateLimitStatusListeners + ", auth=" + auth + '}'; + } + + protected void addParameterToList(final List params, final String paramName, final Boolean param) { + if (param != null) { + params.add(new HttpParameter(paramName, param)); + } + } + + protected void addParameterToList(final List params, final String paramName, final Double param) { + if (param != null) { + params.add(new HttpParameter(paramName, param)); + } + } + + protected void addParameterToList(final List params, final String paramName, final Integer param) { + if (param != null) { + params.add(new HttpParameter(paramName, param)); + } + } + + protected void addParameterToList(final List params, final String paramName, final String param) { + if (param != null) { + params.add(new HttpParameter(paramName, param)); + } + } + + /** + * Check the existence, and the type of the specified file. + * + * @param image image to be uploaded + * @throws twitter4j.TwitterException when the specified file is not found + * (FileNotFoundException will be nested) , or when the + * specified file object is not representing a file(IOException + * will be nested). + */ + protected void checkFileValidity(final File image) throws TwitterException { + if (!image.exists()) // noinspection ThrowableInstanceNeverThrown + throw new TwitterException(new FileNotFoundException(image + " is not found.")); + if (!image.isFile()) // noinspection ThrowableInstanceNeverThrown + throw new TwitterException(new IOException(image + " is not a file.")); + } + + protected final void ensureAuthorizationEnabled() { + if (!auth.isEnabled()) + throw new IllegalStateException( + "Authentication credentials are missing. See http://twitter4j.org/configuration.html for the detail."); + } + + protected final void ensureOAuthEnabled() { + if (!(auth instanceof OAuthAuthorization)) + throw new IllegalStateException( + "OAuth required. Authentication credentials are missing. See http://twitter4j.org/configuration.html for the detail."); + } + + protected User fillInIDAndScreenName() throws TwitterException { + ensureAuthorizationEnabled(); + final HttpParameter[] params = {new HttpParameter("include_entities", conf.isIncludeEntitiesEnabled())}; + final User user = factory.createUser(http.get(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_VERIFY_CREDENTIALS, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_VERIFY_CREDENTIALS, params, auth)); + screenName = user.getScreenName(); + id = user.getId(); + return user; + } + + protected HttpResponse get(final String url, final String signUrl, final HttpParameter... parameters) + throws TwitterException { + // intercept HTTP call for monitoring purposes + HttpResponse response = null; + final long start = System.currentTimeMillis(); + try { + response = http.get(url, signUrl, parameters, auth); + } finally { + final long elapsedTime = System.currentTimeMillis() - start; + TwitterAPIMonitor.getInstance().methodCalled(url, elapsedTime, isOk(response)); + } + return response; + } + + protected boolean isOk(final HttpResponse response) { + return response != null && response.getStatusCode() < 300; + } + + protected HttpParameter[] mergeParameters(final Paging paging, final HttpParameter... params2) { + if (paging == null) { + return params2; + } + return mergeParameters(paging.asPostParameterArray(), params2); + } + + protected HttpParameter[] mergeParameters(final HttpParameter[] params1, final HttpParameter... params2) { + if (params1 != null && params2 != null) { + final HttpParameter[] params = new HttpParameter[params1.length + params2.length]; + System.arraycopy(params1, 0, params, 0, params1.length); + System.arraycopy(params2, 0, params, params1.length, params2.length); + return params; + } + if (null == params1 && null == params2) return new HttpParameter[0]; + if (params1 != null) + return params1; + else + return params2; + } + + protected HttpResponse post(final String url, final String sign_url, final HttpParameter... parameters) + throws TwitterException { + // intercept HTTP call for monitoring purposes + HttpResponse response = null; + final long start = System.currentTimeMillis(); + try { + response = http.post(url, sign_url, parameters, auth); + } finally { + final long elapsedTime = System.currentTimeMillis() - start; + TwitterAPIMonitor.getInstance().methodCalled(url, elapsedTime, isOk(response)); + } + return response; + } + + protected void setFactory() { + factory = new InternalJSONFactoryImpl(conf); + } + + private OAuthSupport getOAuth() { + if (!(auth instanceof OAuthSupport)) + throw new IllegalStateException("OAuth consumer key/secret combination not supplied"); + return (OAuthSupport) auth; + } + + private void init() { + if (null == auth) { + // try to populate OAuthAuthorization if available in the + // configuration + final String consumerKey = conf.getOAuthConsumerKey(); + final String consumerSecret = conf.getOAuthConsumerSecret(); + // try to find oauth tokens in the configuration + if (consumerKey != null && consumerSecret != null) { + final OAuthAuthorization oauth = new OAuthAuthorization(conf); + final String accessToken = conf.getOAuthAccessToken(); + final String accessTokenSecret = conf.getOAuthAccessTokenSecret(); + if (accessToken != null && accessTokenSecret != null) { + oauth.setOAuthAccessToken(new AccessToken(accessToken, accessTokenSecret)); + } + auth = oauth; + } else { + auth = NullAuthorization.getInstance(); + } + } + http = new HttpClientWrapper(conf); + http.setHttpResponseListener(this); + setFactory(); + } + + @SuppressWarnings("unchecked") + private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException { + conf = (Configuration) stream.readObject(); + auth = (Authorization) stream.readObject(); + rateLimitStatusListeners = (List) stream.readObject(); + http = new HttpClientWrapper(conf); + http.setHttpResponseListener(this); + setFactory(); + } + + private void writeObject(final ObjectOutputStream out) throws IOException { + out.writeObject(conf); + out.writeObject(auth); + final List serializableRateLimitStatusListeners = new ArrayList( + 0); + for (final RateLimitStatusListener listener : rateLimitStatusListeners) { + if (listener instanceof Serializable) { + serializableRateLimitStatusListeners.add(listener); + } + } + out.writeObject(serializableRateLimitStatusListeners); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterConstants.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterConstants.java new file mode 100644 index 00000000..204b7a3a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterConstants.java @@ -0,0 +1,144 @@ +package twitter4j; + +public interface TwitterConstants { + + public static final String DEFAULT_OAUTH_BASE_URL = "https://api.twitter.com/oauth/"; + public static final String DEFAULT_SIGNING_OAUTH_BASE_URL = DEFAULT_OAUTH_BASE_URL; + + public static final String PATH_SEGMENT_AUTHENTICATION = "authenticate"; + public static final String PATH_SEGMENT_REQUEST_TOKEN = "request_token"; + public static final String PATH_SEGMENT_ACCESS_TOKEN = "access_token"; + public static final String PATH_SEGMENT_AUTHORIZATION = "authorize"; + + public static final String DEFAULT_OAUTH_REQUEST_TOKEN_URL = DEFAULT_OAUTH_BASE_URL + PATH_SEGMENT_REQUEST_TOKEN; + public static final String DEFAULT_OAUTH_AUTHORIZATION_URL = DEFAULT_OAUTH_BASE_URL + PATH_SEGMENT_AUTHORIZATION; + public static final String DEFAULT_OAUTH_ACCESS_TOKEN_URL = DEFAULT_OAUTH_BASE_URL + PATH_SEGMENT_ACCESS_TOKEN; + public static final String DEFAULT_OAUTH_AUTHENTICATION_URL = DEFAULT_OAUTH_BASE_URL + PATH_SEGMENT_AUTHENTICATION; + + public static final String DEFAULT_SIGNING_OAUTH_REQUEST_TOKEN_URL = DEFAULT_SIGNING_OAUTH_BASE_URL + + PATH_SEGMENT_REQUEST_TOKEN; + public static final String DEFAULT_SIGNING_OAUTH_AUTHORIZATION_URL = DEFAULT_SIGNING_OAUTH_BASE_URL + + PATH_SEGMENT_AUTHORIZATION; + public static final String DEFAULT_SIGNING_OAUTH_ACCESS_TOKEN_URL = DEFAULT_SIGNING_OAUTH_BASE_URL + + PATH_SEGMENT_ACCESS_TOKEN; + public static final String DEFAULT_SIGNING_OAUTH_AUTHENTICATION_URL = DEFAULT_SIGNING_OAUTH_BASE_URL + + PATH_SEGMENT_AUTHENTICATION; + + public static final String DEFAULT_REST_BASE_URL = "https://api.twitter.com/1.1/"; + public static final String DEFAULT_SIGNING_REST_BASE_URL = DEFAULT_REST_BASE_URL; + + public static final String ENDPOINT_ACCOUNT_REMOVE_PROFILE_BANNER = "account/remove_profile_banner.json"; + public static final String ENDPOINT_ACCOUNT_SETTINGS = "account/settings.json"; + public static final String ENDPOINT_ACCOUNT_UPDATE_PROFILE = "account/update_profile.json"; + public static final String ENDPOINT_ACCOUNT_UPDATE_PROFILE_BACKGROUND_IMAGE = "account/update_profile_background_image.json"; + public static final String ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER = "account/update_profile_banner.json"; + public static final String ENDPOINT_ACCOUNT_UPDATE_PROFILE_COLORS = "account/update_profile_colors.json"; + public static final String ENDPOINT_ACCOUNT_UPDATE_PROFILE_IMAGE = "account/update_profile_image.json"; + public static final String ENDPOINT_ACCOUNT_VERIFY_CREDENTIALS = "account/verify_credentials.json"; + + public static final String ENDPOINT_ACTIVITY_ABOUT_ME = "activity/about_me.json"; + public static final String ENDPOINT_ACTIVITY_BY_FRIENDS = "activity/by_friends.json"; + + public static final String ENDPOINT_CONVERSATION_SHOW = "conversation/show.json"; + + public static final String ENDPOINT_TRANSLATIONS_SHOW = "translations/show.json"; + + public static final String ENDPOINT_BLOCKS_CREATE = "blocks/create.json"; + public static final String ENDPOINT_BLOCKS_DESTROY = "blocks/destroy.json"; + public static final String ENDPOINT_BLOCKS_LIST = "blocks/list.json"; + public static final String ENDPOINT_BLOCKS_IDS = "blocks/ids.json"; + + public static final String ENDPOINT_MUTES_USERS_CREATE = "mutes/users/create.json"; + public static final String ENDPOINT_MUTES_USERS_DESTROY = "mutes/users/destroy.json"; + public static final String ENDPOINT_MUTES_USERS_LIST = "mutes/users/list.json"; + public static final String ENDPOINT_MUTES_USERS_IDS = "mutes/users/ids.json"; + + public static final String ENDPOINT_DIRECT_MESSAGES = "direct_messages.json"; + public static final String ENDPOINT_DIRECT_MESSAGES_DESTROY = "direct_messages/destroy.json"; + public static final String ENDPOINT_DIRECT_MESSAGES_NEW = "direct_messages/new.json"; + public static final String ENDPOINT_DIRECT_MESSAGES_SENT = "direct_messages/sent.json"; + public static final String ENDPOINT_DIRECT_MESSAGES_SHOW = "direct_messages/show.json"; + + public static final String TEMPLATE_DM_CONVERSATION_DELETE = "dm/conversation/%d-%d/delete.json"; + + public static final String ENDPOINT_FAVORITES_LIST = "favorites/list.json"; + public static final String ENDPOINT_FAVORITES_CREATE = "favorites/create.json"; + public static final String ENDPOINT_FAVORITES_DESTROY = "favorites/destroy.json"; + + public static final String ENDPOINT_GEO_PLACE = "geo/place.json"; + public static final String ENDPOINT_GEO_REVERSE_GEOCODE = "geo/reverse_geocode.json"; + public static final String ENDPOINT_GEO_SEARCH = "geo/search.json"; + public static final String ENDPOINT_GEO_SIMILAR_PLACES = "geo/similar_places.json"; + + public static final String ENDPOINT_FOLLOWERS_IDS = "followers/ids.json"; + public static final String ENDPOINT_FRIENDS_IDS = "friends/ids.json"; + public static final String ENDPOINT_FOLLOWERS_LIST = "followers/list.json"; + public static final String ENDPOINT_FRIENDS_LIST = "friends/list.json"; + public static final String ENDPOINT_FRIENDSHIPS_CREATE = "friendships/create.json"; + public static final String ENDPOINT_FRIENDSHIPS_DESTROY = "friendships/destroy.json"; + public static final String ENDPOINT_FRIENDSHIPS_INCOMING = "friendships/incoming.json"; + public static final String ENDPOINT_FRIENDSHIPS_LOOKUP = "friendships/lookup.json"; + public static final String ENDPOINT_FRIENDSHIPS_OUTGOING = "friendships/outgoing.json"; + public static final String ENDPOINT_FRIENDSHIPS_SHOW = "friendships/show.json"; + public static final String ENDPOINT_FRIENDSHIPS_UPDATE = "friendships/update.json"; + public static final String ENDPOINT_FRIENDSHIPS_ACCEPT = "friendships/accept.json"; + public static final String ENDPOINT_FRIENDSHIPS_DENY = "friendships/deny.json"; + + public static final String ENDPOINT_HELP_CONFIGURATION = "help/configuration.json"; + public static final String ENDPOINT_HELP_LANGUAGES = "help/languages.json"; + public static final String ENDPOINT_LEGAL_PRIVACY = "legal/privacy.json"; + public static final String ENDPOINT_LEGAL_TOS = "legal/tos.json"; + + public static final String ENDPOINT_LISTS_CREATE = "lists/create.json"; + public static final String ENDPOINT_LISTS_DESTROY = "lists/destroy.json"; + public static final String ENDPOINT_LISTS_LIST = "lists/list.json"; + public static final String ENDPOINT_LISTS_MEMBERSHIPS = "lists/memberships.json"; + public static final String ENDPOINT_LISTS_MEMBERS = "lists/members.json"; + public static final String ENDPOINT_LISTS_MEMBERS_CREATE = "lists/members/create.json"; + public static final String ENDPOINT_LISTS_MEMBERS_CREATE_ALL = "lists/members/create_all.json"; + public static final String ENDPOINT_LISTS_MEMBERS_DESTROY = "lists/members/destroy.json"; + public static final String ENDPOINT_LISTS_MEMBERS_DESTROY_ALL = "lists/members/destroy_all.json"; + public static final String ENDPOINT_LISTS_MEMBERS_SHOW = "lists/members/show.json"; + public static final String ENDPOINT_LISTS_SHOW = "lists/show.json"; + public static final String ENDPOINT_LISTS_STATUSES = "lists/statuses.json"; + public static final String ENDPOINT_LISTS_SUBSCRIPTIONS = "lists/subscriptions.json"; + public static final String ENDPOINT_LISTS_SUBSCRIBERS = "lists/subscribers.json"; + public static final String ENDPOINT_LISTS_SUBSCRIBERS_CREATE = "lists/subscribers/create.json"; + public static final String ENDPOINT_LISTS_SUBSCRIBERS_DESTROY = "lists/subscribers/destroy.json"; + public static final String ENDPOINT_LISTS_SUBSCRIBERS_SHOW = "lists/subscribers/show.json"; + public static final String ENDPOINT_LISTS_UPDATE = "lists/update.json"; + public static final String ENDPOINT_LISTS_OWNERSHIPS = "lists/ownerships.json"; + + public static final String ENDPOINT_RATE_LIMIT_STATUS = "application/rate_limit_status.json"; + + public static final String ENDPOINT_SAVED_SEARCHES_CREATE = "saved_searches/create.json"; + public static final String ENDPOINT_SAVED_SEARCHES_LIST = "saved_searches/list.json"; + + public static final String ENDPOINT_SEARCH_TWEETS = "search/tweets.json"; + + public static final String ENDPOINT_STATUSES_HOME_TIMELINE = "statuses/home_timeline.json"; + public static final String ENDPOINT_STATUSES_MENTIONS_TIMELINE = "statuses/mentions_timeline.json"; + public static final String ENDPOINT_STATUSES_OEMBED = "statuses/oembed.json"; + public static final String ENDPOINT_STATUSES_RETWEETS_OF_ME = "statuses/retweets_of_me.json"; + public static final String ENDPOINT_STATUSES_RETWEETERS_IDS = "statuses/retweeters/ids.json"; + public static final String ENDPOINT_STATUSES_SHOW = "statuses/show.json"; + public static final String ENDPOINT_STATUSES_UPDATE = "statuses/update.json"; + public static final String ENDPOINT_STATUSES_USER_TIMELINE = "statuses/user_timeline.json"; + public static final String ENDPOINT_STATUSES_MEDIA_TIMELINE = "statuses/media_timeline.json"; + public static final String ENDPOINT_STATUSES_REPORT_SPAM = "statuses/report_spam.json"; + + public static final String ENDPOINT_TRENDS_AVAILABLE = "trends/available.json"; + public static final String ENDPOINT_TRENDS_CLOSEST = "trends/closest.json"; + public static final String ENDPOINT_TRENDS_PLACE = "trends/place.json"; + + public static final String ENDPOINT_USERS_LOOKUP = "users/lookup.json"; + public static final String ENDPOINT_USERS_REPORT_SPAM = "users/report_spam.json"; + public static final String ENDPOINT_USERS_SEARCH = "users/search.json"; + public static final String ENDPOINT_USERS_SHOW = "users/show.json"; + public static final String ENDPOINT_USERS_SUGGESTIONS = "users/suggestions.json"; + + public static final String DEFAULT_UPLOAD_BASE_URL = "https://upload.twitter.com/1.1/"; + public static final String DEFAULT_SIGNING_UPLOAD_BASE_URL = DEFAULT_UPLOAD_BASE_URL; + + public static final String ENDPOINT_MEDIA_UPLOAD = "media/upload.json"; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterException.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterException.java new file mode 100644 index 00000000..2e41e9e8 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterException.java @@ -0,0 +1,318 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.List; +import java.util.Locale; + +import twitter4j.http.HttpRequest; +import twitter4j.http.HttpResponse; +import twitter4j.http.HttpResponseCode; +import twitter4j.internal.json.InternalJSONFactoryImpl; +import twitter4j.internal.util.InternalParseUtil; + +import static twitter4j.internal.util.InternalParseUtil.getInt; + +/** + * An exception class that will be thrown when TwitterAPI calls are failed.
+ * In case the Twitter server returned HTTP error code, you can get the HTTP + * status code using getStatusCode() method. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public class TwitterException extends Exception implements TwitterResponse, HttpResponseCode { + private int statusCode = -1; + private int errorCode = -1; + private static final long serialVersionUID = -2623309261327598087L; + private ExceptionDiagnosis exceptionDiagnosis = null; + private HttpResponse response; + private String errorMessage = null; + private HttpRequest request; + + private final static String[] FILTER = new String[]{"twitter4j"}; + + boolean nested = false; + + public TwitterException(final Exception cause) { + this(cause.getMessage(), cause); + if (cause instanceof TwitterException) { + ((TwitterException) cause).setNested(); + } + } + + public TwitterException(final String message) { + this(message, (Throwable) null); + } + + public TwitterException(final String message, final Exception cause, final int statusCode) { + this(message, cause); + this.statusCode = statusCode; + } + + public TwitterException(final String message, final HttpRequest req, final HttpResponse res) { + this(message); + response = res; + request = req; + statusCode = res != null ? res.getStatusCode() : -1; + if (response != null) { + try { + decode(response.asString()); + } catch (TwitterException ignore) { + } + } + } + + public TwitterException(final String message, final HttpResponse res) { + this(message, null, res); + } + + public TwitterException(final String message, final Throwable cause) { + super(message, cause); + decode(message); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final TwitterException that = (TwitterException) o; + + if (errorCode != that.errorCode) return false; + if (nested != that.nested) return false; + if (statusCode != that.statusCode) return false; + if (errorMessage != null ? !errorMessage.equals(that.errorMessage) : that.errorMessage != null) + return false; + if (exceptionDiagnosis != null ? !exceptionDiagnosis.equals(that.exceptionDiagnosis) + : that.exceptionDiagnosis != null) return false; + if (response != null ? !response.equals(that.response) : that.response != null) + return false; + + return true; + } + + /** + * Tests if the exception is caused by rate limitation exceed + * + * @return if the exception is caused by rate limitation exceed + * @see Rate Limiting | + * Twitter Developers + * @since Twitter4J 2.1.2 + */ + public boolean exceededRateLimitation() { + return statusCode == 400 && getRateLimitStatus() != null // REST API + || statusCode == ENHANCE_YOUR_CLAIM // Streaming API + || statusCode == TOO_MANY_REQUESTS; // API 1.1 + } + + /** + * {@inheritDoc} + */ + @Override + public int getAccessLevel() { + return InternalParseUtil.toAccessLevel(response); + } + + public int getErrorCode() { + return errorCode; + } + + /** + * Returns error message from the API if available. + * + * @return error message from the API + * @since Twitter4J 2.2.3 + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Returns a hexadecimal representation of this exception stacktrace.
+ * An exception code is a hexadecimal representation of the stacktrace which + * enables it easier to Google known issues.
+ * Format : XXXXXXXX:YYYYYYYY[ XX:YY]
+ * Where XX is a hash code of stacktrace without line number
+ * YY is a hash code of stacktrace excluding line number
+ * [-XX:YY] will appear when this instance a root cause + * + * @return a hexadecimal representation of this exception stacktrace + */ + public String getExceptionCode() { + return getExceptionDiagnosis().asHexString(); + } + + public HttpRequest getHttpRequest() { + return request; + } + + public HttpResponse getHttpResponse() { + return response; + } + + /** + * {@inheritDoc} + */ + @Override + public String getMessage() { + if (errorMessage != null && errorCode != -1) + return String.format(Locale.US, "Error %d: %s", errorCode, errorMessage); + else if (statusCode != -1) + return String.format(Locale.US, "Error %d", statusCode); + else + return super.getMessage(); + } + + /** + * {@inheritDoc} + * + * @since Twitter4J 2.1.2 + */ + @Override + public RateLimitStatus getRateLimitStatus() { + if (null == response) return null; + return InternalJSONFactoryImpl.createRateLimitStatusFromResponseHeader(response); + } + + public String getResponseHeader(final String name) { + String value = null; + if (response != null) { + final List header = response.getResponseHeaderFields().get(name); + if (header.size() > 0) { + value = header.get(0); + } + } + return value; + } + + /** + * Returns int value of "Retry-After" response header (Search API) or + * seconds_until_reset (REST API). An application that exceeds the rate + * limitations of the Search API will receive HTTP 420 response codes to + * requests. It is a best practice to watch for this error condition and + * honor the Retry-After header that instructs the application when it is + * safe to continue. The Retry-After header's value is the number of seconds + * your application should wait before submitting another query (for + * example: Retry-After: 67).
+ * Check if getStatusCode() == 503 before calling this method to ensure that + * you are actually exceeding rate limitation with query apis.
+ * + * @return instructs the application when it is safe to continue in seconds + * @see Rate Limiting | + * Twitter Developers + * @since Twitter4J 2.1.0 + */ + public int getRetryAfter() { + int retryAfter = -1; + if (statusCode == 400) { + final RateLimitStatus rateLimitStatus = getRateLimitStatus(); + if (rateLimitStatus != null) { + retryAfter = rateLimitStatus.getSecondsUntilReset(); + } + } else if (statusCode == ENHANCE_YOUR_CLAIM) { + try { + final String retryAfterStr = response.getResponseHeader("Retry-After"); + if (retryAfterStr != null) { + retryAfter = Integer.valueOf(retryAfterStr); + } + } catch (final NumberFormatException ignore) { + } + } + return retryAfter; + } + + public int getStatusCode() { + return statusCode; + } + + @Override + public int hashCode() { + int result = statusCode; + result = 31 * result + errorCode; + result = 31 * result + (exceptionDiagnosis != null ? exceptionDiagnosis.hashCode() : 0); + result = 31 * result + (response != null ? response.hashCode() : 0); + result = 31 * result + (errorMessage != null ? errorMessage.hashCode() : 0); + result = 31 * result + (nested ? 1 : 0); + return result; + } + + /** + * Tests if the exception is caused by network issue + * + * @return if the exception is caused by network issue + * @since Twitter4J 2.1.2 + */ + public boolean isCausedByNetworkIssue() { + return getCause() instanceof java.io.IOException; + } + + /** + * Tests if error message from the API is available + * + * @return true if error message from the API is available + * @since Twitter4J 2.2.3 + */ + public boolean isErrorMessageAvailable() { + return errorMessage != null; + } + + /** + * Tests if the exception is caused by non-existing resource + * + * @return if the exception is caused by non-existing resource + * @since Twitter4J 2.1.2 + */ + public boolean resourceNotFound() { + return statusCode == NOT_FOUND; + } + + @Override + public String toString() { + return getMessage(); + } + + private void decode(final String str) { + if (str != null && str.startsWith("{")) { + try { + final JSONObject json = new JSONObject(str); + if (!json.isNull("errors")) { + final JSONObject error = json.getJSONArray("errors").getJSONObject(0); + errorMessage = error.getString("message"); + errorCode = getInt("code", error); + } + } catch (final JSONException ignore) { + } + } + } + + private ExceptionDiagnosis getExceptionDiagnosis() { + if (null == exceptionDiagnosis) { + exceptionDiagnosis = new ExceptionDiagnosis(this, FILTER); + } + return exceptionDiagnosis; + } + + void setNested() { + nested = true; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterFactory.java new file mode 100644 index 00000000..e48234fe --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterFactory.java @@ -0,0 +1,111 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import twitter4j.auth.AccessToken; +import twitter4j.auth.Authorization; +import twitter4j.auth.AuthorizationFactory; +import twitter4j.auth.OAuthAuthorization; +import twitter4j.conf.Configuration; +import twitter4j.conf.ConfigurationContext; + +/** + * A factory class for Twitter.
+ * An instance of this class is completely thread safe and can be re-used and + * used concurrently. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.0 + */ +public final class TwitterFactory { + /* AsyncTwitterFactory and TWitterStream will access this field */ + static final Authorization DEFAULT_AUTHORIZATION = AuthorizationFactory.getInstance(ConfigurationContext + .getInstance()); + private static final Twitter SINGLETON; + + private final Configuration conf; + + static { + SINGLETON = new TwitterImpl(ConfigurationContext.getInstance(), DEFAULT_AUTHORIZATION); + } + + /** + * Creates a TwitterFactory with the root configuration. + */ + public TwitterFactory() { + this(ConfigurationContext.getInstance()); + } + + /** + * Creates a TwitterFactory with the given configuration. + * + * @param conf the configuration to use + * @since Twitter4J 2.1.1 + */ + public TwitterFactory(final Configuration conf) { + if (conf == null) throw new NullPointerException("configuration cannot be null"); + this.conf = conf; + } + + /** + * Returns a instance associated with the configuration bound to this + * factory. + * + * @return default singleton instance + */ + public Twitter getInstance() { + return getInstance(AuthorizationFactory.getInstance(conf)); + } + + /** + * Returns a OAuth Authenticated instance.
+ * consumer key and consumer Secret must be provided by + * twitter4j.properties, or system properties.
+ * Unlike {@link twitter4j.Twitter#setOAuthAccessToken(twitter4j.auth.AccessToken)} , + * this factory method potentially returns a cached instance. + * + * @param accessToken access token + * @return an instance + * @since Twitter4J 2.1.9 + */ + public Twitter getInstance(final AccessToken accessToken) { + final String consumerKey = conf.getOAuthConsumerKey(); + final String consumerSecret = conf.getOAuthConsumerSecret(); + if (null == consumerKey && null == consumerSecret) + throw new IllegalStateException("Consumer key and Consumer secret not supplied."); + final OAuthAuthorization oauth = new OAuthAuthorization(conf); + oauth.setOAuthAccessToken(accessToken); + return getInstance(oauth); + } + + public Twitter getInstance(final Authorization auth) { + return new TwitterImpl(conf, auth); + } + + /** + * Returns default singleton Twitter instance. + * + * @return default singleton Twitter instance + * @since Twitter4J 2.2.4 + */ + public static Twitter getSingleton() { + return SINGLETON; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterImpl.java new file mode 100644 index 00000000..6028695f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterImpl.java @@ -0,0 +1,1716 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import org.json.JSONException; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import twitter4j.auth.Authorization; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpParameter; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalStringUtil; + +import static twitter4j.http.HttpParameter.getParameterArray; + +/** + * A java representation of the Twitter REST API
+ * This class is thread safe and can be cached/re-used and used concurrently.
+ * Currently this class is not carefully designed to be extended. It is + * suggested to extend this class only for mock testing purpose.
+ * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +final class TwitterImpl extends TwitterBaseImpl implements Twitter { + + private final HttpParameter INCLUDE_ENTITIES; + private final HttpParameter INCLUDE_RTS; + private final HttpParameter INCLUDE_MY_RETWEET; + private final HttpParameter INCLUDE_REPLY_COUNT; + private final HttpParameter INCLUDE_DESCENDENT_REPLY_COUNT; + private final HttpParameter INCLUDE_CARDS; + private final HttpParameter CARDS_PLATFORM; + + /* package */ + TwitterImpl(final Configuration conf, final Authorization auth) { + super(conf, auth); + INCLUDE_ENTITIES = new HttpParameter("include_entities", conf.isIncludeEntitiesEnabled()); + INCLUDE_RTS = new HttpParameter("include_rts", conf.isIncludeRTsEnabled()); + INCLUDE_MY_RETWEET = new HttpParameter("include_my_retweet", 1); + INCLUDE_REPLY_COUNT = new HttpParameter("include_reply_count", conf.isIncludeReplyCountEnabled()); + INCLUDE_DESCENDENT_REPLY_COUNT = new HttpParameter("include_descendent_reply_count", conf.isIncludeDescendentReplyCountEnabled()); + INCLUDE_CARDS = new HttpParameter("include_cards", conf.isIncludeCardsEnabled()); + CARDS_PLATFORM = new HttpParameter("cards_platform", conf.getCardsPlatform()); + } + + @Override + public User acceptFriendship(final long userId) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_ACCEPT; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_ACCEPT; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId))); + } + + @Override + public User acceptFriendship(final String screenName) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_ACCEPT; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_ACCEPT; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName))); + } + + @Override + public UserList addUserListMember(final long listId, final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE, new HttpParameter("list_id", listId), + new HttpParameter("list_id", listId))); + } + + @Override + public UserList addUserListMember(final long listId, final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE, new HttpParameter("list_id", listId), + new HttpParameter("screen_name", screenName))); + } + + @Override + public UserList addUserListMembers(final long listId, final long[] userIds) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE_ALL, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE_ALL, new HttpParameter("list_id", listId), + new HttpParameter("user_id", InternalStringUtil.join(userIds)))); + } + + @Override + public UserList addUserListMembers(final long listId, final String[] screenNames) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE_ALL, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_CREATE_ALL, new HttpParameter("list_id", listId), + new HttpParameter("screen_name", InternalStringUtil.join(screenNames)))); + } + + @Override + public User createBlock(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_BLOCKS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_BLOCKS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public User createBlock(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_BLOCKS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_BLOCKS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName), + INCLUDE_ENTITIES)); + } + + @Override + public Status createFavorite(final long id) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_CREATE; + return factory.createStatus(post(url, signUrl, new HttpParameter("id", id), INCLUDE_ENTITIES, + INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT)); + } + + @Override + public User createFriendship(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId))); + } + + @Override + public User createFriendship(final long userId, final boolean follow) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId), new HttpParameter("follow", + follow))); + } + + @Override + public User createFriendship(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName))); + } + + @Override + public User createFriendship(final String screenName, final boolean follow) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName), new HttpParameter( + "follow", follow))); + } + + @Override + public User createMute(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public User createMute(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_CREATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_CREATE; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName), INCLUDE_ENTITIES)); + } + + @Override + public Place createPlace(final String name, final String containedWithin, final String token, + final GeoLocation location, final String streetAddress) throws TwitterException { + ensureAuthorizationEnabled(); + final List params = new ArrayList<>(6); + addParameterToList(params, "name", name); + addParameterToList(params, "contained_within", containedWithin); + addParameterToList(params, "token", token); + addParameterToList(params, "lat", location.getLatitude()); + addParameterToList(params, "long", location.getLongitude()); + addParameterToList(params, "attribute:street_address", streetAddress); + return factory.createPlace(post(conf.getRestBaseURL() + ENDPOINT_GEO_PLACE, conf.getSigningRestBaseURL() + + ENDPOINT_GEO_PLACE, params.toArray(new HttpParameter[params.size()]))); + } + + @Override + public SavedSearch createSavedSearch(final String query) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createSavedSearch(post(conf.getRestBaseURL() + ENDPOINT_SAVED_SEARCHES_CREATE, + conf.getSigningRestBaseURL() + ENDPOINT_SAVED_SEARCHES_CREATE, new HttpParameter("query", query))); + } + + @Override + public UserList createUserList(final String listName, final boolean isPublicList, final String description) + throws TwitterException { + ensureAuthorizationEnabled(); + final List params = new ArrayList<>(); + addParameterToList(params, "name", listName); + addParameterToList(params, "mode", isPublicList ? "public" : "private"); + addParameterToList(params, "description", description); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_CREATE, conf.getSigningRestBaseURL() + + ENDPOINT_LISTS_CREATE, params.toArray(new HttpParameter[params.size()]))); + } + + @Override + public UserList createUserListSubscription(final long listId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory + .createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS_CREATE, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS_CREATE, new HttpParameter("list_id", + listId))); + } + + @Override + public UserList deleteUserListMember(final long listId, final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY, new HttpParameter("list_id", listId), + new HttpParameter("user_id", userId))); + } + + @Override + public UserList deleteUserListMember(final long listId, final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY, new HttpParameter("list_id", listId), + new HttpParameter("screen_name", screenName))); + } + + @Override + public UserList deleteUserListMembers(final long listId, final long[] userIds) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY_ALL, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY_ALL, + new HttpParameter("list_id", listId), new HttpParameter("user_id", InternalStringUtil.join(userIds)))); + } + + @Override + public UserList deleteUserListMembers(final long listId, final String[] screenNames) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY_ALL, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS_DESTROY_ALL, + new HttpParameter("list_id", listId), + new HttpParameter("screen_name", InternalStringUtil.join(screenNames)))); + } + + @Override + public User denyFriendship(final long userId) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_DENY; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_DENY; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId))); + } + + @Override + public User denyFriendship(final String screenName) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_DENY; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_DENY; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName))); + } + + @Override + public User destroyBlock(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_BLOCKS_DESTROY, conf.getSigningRestBaseURL() + + ENDPOINT_BLOCKS_DESTROY, new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public User destroyBlock(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_BLOCKS_DESTROY, conf.getSigningRestBaseURL() + + ENDPOINT_BLOCKS_DESTROY, new HttpParameter("screen_name", screenName), INCLUDE_ENTITIES)); + } + + @Override + public DirectMessage destroyDirectMessage(final long id) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessage(post(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_DESTROY, new HttpParameter("id", id), + INCLUDE_ENTITIES)); + } + + @Override + public void destroyDirectMessagesConversation(long userId) throws TwitterException { + final String url = conf.getRestBaseURL() + + String.format(Locale.ROOT, TEMPLATE_DM_CONVERSATION_DELETE, id, userId); + final String signUrl = conf.getSigningRestBaseURL() + + String.format(Locale.ROOT, TEMPLATE_DM_CONVERSATION_DELETE, id, userId); + post(url, signUrl); + } + + @Override + public Status destroyFavorite(final long id) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatus(post(conf.getRestBaseURL() + ENDPOINT_FAVORITES_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_DESTROY, new HttpParameter("id", id), + INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT)); + } + + @Override + public User destroyFriendship(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_DESTROY, new HttpParameter("user_id", userId))); + } + + @Override + public User destroyFriendship(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_DESTROY, new HttpParameter("screen_name", + screenName))); + } + + @Override + public User destroyMute(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_DESTROY; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_DESTROY; + return factory.createUser(post(url, signUrl, new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public User destroyMute(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_DESTROY; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_DESTROY; + return factory.createUser(post(url, signUrl, new HttpParameter("screen_name", screenName), INCLUDE_ENTITIES)); + } + + @Override + public SavedSearch destroySavedSearch(final int id) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createSavedSearch(post(conf.getRestBaseURL() + "saved_searches/destroy/" + id + ".json", + conf.getSigningRestBaseURL() + "saved_searches/destroy/" + id + ".json")); + } + + @Override + public Status destroyStatus(final long statusId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatus(post(conf.getRestBaseURL() + "statuses/destroy/" + statusId + ".json", + conf.getSigningRestBaseURL() + "statuses/destroy/" + statusId + ".json", INCLUDE_ENTITIES, + INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT)); + } + + @Override + public UserList destroyUserList(final long listId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_DESTROY, new HttpParameter("list_id", listId))); + } + + @Override + public UserList destroyUserListSubscription(final long listId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory + .createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS_DESTROY, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS_DESTROY, new HttpParameter("list_id", + listId))); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + final TwitterImpl twitter = (TwitterImpl) o; + + if (!INCLUDE_ENTITIES.equals(twitter.INCLUDE_ENTITIES)) return false; + if (!INCLUDE_RTS.equals(twitter.INCLUDE_RTS)) return false; + + return true; + } + + @Override + public AccountSettings getAccountSettings() throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createAccountSettings(get(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_SETTINGS, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_SETTINGS)); + } + + @Override + public ResponseList getActivitiesAboutMe() throws TwitterException { + return getActivitiesAboutMe(null); + } + + @Override + public ResponseList getActivitiesAboutMe(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createActivityList(get(conf.getRestBaseURL() + ENDPOINT_ACTIVITY_ABOUT_ME, + conf.getSigningRestBaseURL() + ENDPOINT_ACTIVITY_ABOUT_ME, + mergeParameters(paging != null ? paging.asPostParameterArray() : null, INCLUDE_ENTITIES))); + } + + @Override + public ResponseList getActivitiesByFriends() throws TwitterException { + return getActivitiesByFriends(null); + } + + @Override + public ResponseList getActivitiesByFriends(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createActivityList(get(conf.getRestBaseURL() + ENDPOINT_ACTIVITY_BY_FRIENDS, + conf.getSigningRestBaseURL() + ENDPOINT_ACTIVITY_BY_FRIENDS, + mergeParameters(paging != null ? paging.asPostParameterArray() : null, INCLUDE_ENTITIES))); + } + + @Override + public TwitterAPIConfiguration getAPIConfiguration() throws TwitterException { + return factory.createTwitterAPIConfiguration(get(conf.getRestBaseURL() + ENDPOINT_HELP_CONFIGURATION, + conf.getSigningRestBaseURL() + ENDPOINT_HELP_CONFIGURATION)); + } + + @Override + public ResponseList getAvailableTrends() throws TwitterException { + return factory.createLocationList(get(conf.getRestBaseURL() + ENDPOINT_TRENDS_AVAILABLE, + conf.getSigningRestBaseURL() + ENDPOINT_TRENDS_AVAILABLE)); + } + + @Override + public ResponseList getAvailableTrends(final GeoLocation location) throws TwitterException { + return factory.createLocationList(get(conf.getRestBaseURL() + ENDPOINT_TRENDS_AVAILABLE, + conf.getSigningRestBaseURL() + ENDPOINT_TRENDS_AVAILABLE, + new HttpParameter("lat", location.getLatitude()), new HttpParameter("long", location.getLongitude()))); + } + + @Override + public IDs getBlocksIDs() throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_BLOCKS_IDS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_BLOCKS_IDS; + return factory.createIDs(get(url, signUrl)); + } + + @Override + public IDs getBlocksIDs(final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_BLOCKS_IDS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_BLOCKS_IDS; + return factory.createIDs(get(url, signUrl, paging.asPostParameterArray())); + } + + @Override + public PageableResponseList getBlocksList() throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_BLOCKS_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_BLOCKS_LIST; + return factory.createPagableUserList(get(url, signUrl, INCLUDE_ENTITIES)); + } + + @Override + public PageableResponseList getBlocksList(final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_BLOCKS_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_BLOCKS_LIST; + final HttpParameter[] params = mergeParameters(paging.asPostParameterArray(), INCLUDE_ENTITIES); + return factory.createPagableUserList(get(url, signUrl, params)); + } + + @Override + public ResponseList getClosestTrends(final GeoLocation location) throws TwitterException { + return factory.createLocationList(get(conf.getRestBaseURL() + ENDPOINT_TRENDS_CLOSEST, + conf.getSigningRestBaseURL() + ENDPOINT_TRENDS_CLOSEST, + new HttpParameter("lat", location.getLatitude()), new HttpParameter("long", location.getLongitude()))); + } + + @Override + public ResponseList getDirectMessages() throws TwitterException { + return getDirectMessages(null); + } + + @Override + public ResponseList getDirectMessages(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessageList(get(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES, + mergeParameters(paging, INCLUDE_ENTITIES))); + } + + @Override + public ResponseList getFavorites() throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_LIST; + return factory.createStatusList(get(url, signUrl, INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, + INCLUDE_DESCENDENT_REPLY_COUNT, INCLUDE_CARDS, CARDS_PLATFORM)); + } + + @Override + public ResponseList getFavorites(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_LIST; + return factory.createStatusList(get(url, signUrl, new HttpParameter("user_id", userId), + INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT, + INCLUDE_CARDS, CARDS_PLATFORM)); + } + + @Override + public ResponseList getFavorites(final long userId, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_LIST; + return factory.createStatusList(get(url, signUrl, mergeParameters(paging, + new HttpParameter("user_id", userId), INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, + INCLUDE_DESCENDENT_REPLY_COUNT, INCLUDE_CARDS, CARDS_PLATFORM))); + } + + @Override + public ResponseList getFavorites(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_LIST; + return factory.createStatusList(get(url, signUrl, mergeParameters(paging, INCLUDE_ENTITIES, + INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT, INCLUDE_CARDS, CARDS_PLATFORM))); + } + + @Override + public ResponseList getFavorites(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_LIST; + return factory.createStatusList(get(url, signUrl, new HttpParameter("screen_name", screenName), + INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT, INCLUDE_CARDS, + CARDS_PLATFORM)); + } + + @Override + public ResponseList getFavorites(final String screenName, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_FAVORITES_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FAVORITES_LIST; + return factory.createStatusList(get(url, signUrl, mergeParameters(paging.asPostParameterArray(), + new HttpParameter("screen_name", screenName), INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, + INCLUDE_DESCENDENT_REPLY_COUNT, INCLUDE_CARDS, CARDS_PLATFORM))); + } + + @Override + public IDs getFollowersIDs(final CursorPaging paging) throws TwitterException { + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FOLLOWERS_IDS, conf.getSigningRestBaseURL() + + ENDPOINT_FOLLOWERS_IDS, paging.asPostParameterArray())); + } + + @Override + public IDs getFollowersIDs(final long userId, final CursorPaging paging) throws TwitterException { + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FOLLOWERS_IDS, conf.getSigningRestBaseURL() + + ENDPOINT_FOLLOWERS_IDS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("user_id", userId)))); + } + + @Override + public IDs getFollowersIDs(final String screenName, final CursorPaging paging) throws TwitterException { + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FOLLOWERS_IDS, conf.getSigningRestBaseURL() + + ENDPOINT_FOLLOWERS_IDS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("screen_name", screenName)))); + } + + @Override + public PageableResponseList getFollowersList(final CursorPaging paging) throws TwitterException { + return factory.createPagableUserList(get(conf.getRestBaseURL() + ENDPOINT_FOLLOWERS_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_FOLLOWERS_LIST, paging.asPostParameterArray())); + } + + @Override + public PageableResponseList getFollowersList(final long userId, final CursorPaging paging) + throws TwitterException { + return factory.createPagableUserList(get(conf.getRestBaseURL() + ENDPOINT_FOLLOWERS_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_FOLLOWERS_LIST, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("user_id", userId)))); + } + + @Override + public PageableResponseList getFollowersList(final String screenName, final CursorPaging paging) + throws TwitterException { + return factory.createPagableUserList(get(conf.getRestBaseURL() + ENDPOINT_FOLLOWERS_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_FOLLOWERS_LIST, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("screen_name", screenName)))); + } + + @Override + public IDs getFriendsIDs(final CursorPaging paging) throws TwitterException { + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FRIENDS_IDS, conf.getSigningRestBaseURL() + + ENDPOINT_FRIENDS_IDS, paging.asPostParameterArray())); + } + + @Override + public IDs getFriendsIDs(final long userId, final CursorPaging paging) throws TwitterException { + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FRIENDS_IDS, conf.getSigningRestBaseURL() + + ENDPOINT_FRIENDS_IDS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("user_id", userId)))); + } + + @Override + public IDs getFriendsIDs(final String screenName, final CursorPaging paging) throws TwitterException { + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FRIENDS_IDS, conf.getSigningRestBaseURL() + + ENDPOINT_FRIENDS_IDS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("screen_name", screenName)))); + } + + @Override + public PageableResponseList getFriendsList(final CursorPaging paging) throws TwitterException { + return factory.createPagableUserList(get(conf.getRestBaseURL() + ENDPOINT_FRIENDS_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDS_LIST, paging.asPostParameterArray())); + } + + @Override + public PageableResponseList getFriendsList(final long userId, final CursorPaging paging) + throws TwitterException { + return factory.createPagableUserList(get(conf.getRestBaseURL() + ENDPOINT_FRIENDS_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDS_LIST, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("user_id", userId)))); + } + + @Override + public PageableResponseList getFriendsList(final String screenName, final CursorPaging paging) + throws TwitterException { + return factory.createPagableUserList(get(conf.getRestBaseURL() + ENDPOINT_FRIENDS_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDS_LIST, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("screen_name", screenName)))); + } + + @Override + public Place getGeoDetails(final String id) throws TwitterException { + return factory.createPlace(get(conf.getRestBaseURL() + "geo/id/" + id + ".json", conf.getSigningRestBaseURL() + + "geo/id/" + id + ".json")); + } + + @Override + public ResponseList getHomeTimeline() throws TwitterException { + return getHomeTimeline(null); + } + + @Override + public ResponseList getHomeTimeline(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_HOME_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_HOME_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_CARDS); + paramsList.add(CARDS_PLATFORM); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public IDs getIncomingFriendships(final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_INCOMING, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_INCOMING, paging.asPostParameterArray())); + } + + @Override + public ResponseList getLanguages() throws TwitterException { + return factory.createLanguageList(get(conf.getRestBaseURL() + ENDPOINT_HELP_LANGUAGES, + conf.getSigningRestBaseURL() + ENDPOINT_HELP_LANGUAGES)); + } + + @Override + public Trends getLocationTrends(final int woeid) throws TwitterException { + return getPlaceTrends(woeid); + } + + @Override + public ResponseList getMediaTimeline() throws TwitterException { + return getMediaTimeline(new Paging()); + } + + @Override + public ResponseList getMediaTimeline(final long userId) throws TwitterException { + return getMediaTimeline(userId, null); + } + + @Override + public ResponseList getMediaTimeline(final long userId, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_MEDIA_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_MEDIA_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(new HttpParameter("user_id", userId)); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public ResponseList getMediaTimeline(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_MEDIA_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_MEDIA_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_MY_RETWEET); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public ResponseList getMediaTimeline(final String screenName) throws TwitterException { + return getMediaTimeline(screenName, null); + } + + @Override + public ResponseList getMediaTimeline(final String screenName, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_MEDIA_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_MEDIA_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(new HttpParameter("screen_name", screenName)); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public ResponseList getMemberSuggestions(final String categorySlug) throws TwitterException { + final HttpResponse res = get(conf.getRestBaseURL() + "users/suggestions/" + categorySlug + "/members.json", + conf.getSigningRestBaseURL() + "users/suggestions/" + categorySlug + "/members.json"); + return factory.createUserListFromJSONArray(res); + } + + @Override + public ResponseList getMentionsTimeline() throws TwitterException { + ensureAuthorizationEnabled(); + return getMentionsTimeline(null); + } + + @Override + public ResponseList getMentionsTimeline(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_MENTIONS_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_MENTIONS_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(INCLUDE_CARDS); + paramsList.add(CARDS_PLATFORM); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public IDs getMutesUsersIDs() throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_IDS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_IDS; + return factory.createIDs(get(url, signUrl)); + } + + @Override + public IDs getMutesUsersIDs(final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_IDS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_IDS; + return factory.createIDs(get(url, signUrl, paging.asPostParameterArray())); + } + + @Override + public PageableResponseList getMutesUsersList() throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_LIST; + return factory.createPagableUserList(get(url, signUrl, INCLUDE_ENTITIES)); + } + + @Override + public PageableResponseList getMutesUsersList(final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_MUTES_USERS_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_MUTES_USERS_LIST; + final HttpParameter[] params = mergeParameters(paging.asPostParameterArray(), INCLUDE_ENTITIES); + return factory.createPagableUserList(get(url, signUrl, params)); + } + + @Override + public OEmbed getOEmbed(final OEmbedRequest req) throws TwitterException { + return factory.createOEmbed(get(conf.getRestBaseURL() + ENDPOINT_STATUSES_OEMBED, conf.getRestBaseURL() + + ENDPOINT_STATUSES_OEMBED, req.asHttpParameterArray())); + } + + @Override + public IDs getOutgoingFriendships(final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_OUTGOING, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_OUTGOING, paging.asPostParameterArray())); + } + + @Override + public Trends getPlaceTrends(final int woeid) throws TwitterException { + return factory.createTrends(get(conf.getRestBaseURL() + ENDPOINT_TRENDS_PLACE, conf.getSigningRestBaseURL() + + ENDPOINT_TRENDS_PLACE, new HttpParameter("id", woeid))); + } + + @Override + public String getPrivacyPolicy() throws TwitterException { + try { + return get(conf.getRestBaseURL() + ENDPOINT_LEGAL_PRIVACY, + conf.getSigningRestBaseURL() + ENDPOINT_LEGAL_PRIVACY).asJSONObject().getString("privacy"); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + @Override + public Map getRateLimitStatus() throws TwitterException { + return factory.createRateLimitStatus(get(conf.getRestBaseURL() + ENDPOINT_RATE_LIMIT_STATUS, + conf.getSigningRestBaseURL() + ENDPOINT_RATE_LIMIT_STATUS)); + } + + @Override + public Map getRateLimitStatus(final String... resources) throws TwitterException { + return factory.createRateLimitStatus(get(conf.getRestBaseURL() + ENDPOINT_RATE_LIMIT_STATUS, + conf.getSigningRestBaseURL() + ENDPOINT_RATE_LIMIT_STATUS, new HttpParameter("resources", + InternalStringUtil.join(resources)))); + } + + @Override + public IDs getRetweetersIDs(final long statusId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_STATUSES_RETWEETERS_IDS, + conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_RETWEETERS_IDS, new HttpParameter("id", statusId))); + } + + @Override + public IDs getRetweetersIDs(final long statusId, final CursorPaging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createIDs(get(conf.getRestBaseURL() + ENDPOINT_STATUSES_RETWEETERS_IDS, + conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_RETWEETERS_IDS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("id", statusId)))); + } + + @Override + public ResponseList getRetweets(final long statusId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatusList(get(conf.getRestBaseURL() + "statuses/retweets/" + statusId + ".json", + conf.getSigningRestBaseURL() + "statuses/retweets/" + statusId + ".json", INCLUDE_ENTITIES)); + } + + @Override + public ResponseList getRetweets(final long statusId, final int count) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatusList(get(conf.getRestBaseURL() + "statuses/retweets/" + statusId + ".json", + conf.getSigningRestBaseURL() + "statuses/retweets/" + statusId + ".json", new HttpParameter("count", + count), INCLUDE_ENTITIES)); + } + + @Override + public ResponseList getRetweetsOfMe() throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatusList(get(conf.getRestBaseURL() + ENDPOINT_STATUSES_RETWEETS_OF_ME, + conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_RETWEETS_OF_ME, INCLUDE_ENTITIES, INCLUDE_RTS)); + } + + @Override + public ResponseList getRetweetsOfMe(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatusList(get(conf.getRestBaseURL() + ENDPOINT_STATUSES_RETWEETS_OF_ME, + conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_RETWEETS_OF_ME, + mergeParameters(paging.asPostParameterArray(), INCLUDE_RTS, INCLUDE_ENTITIES))); + } + + @Override + public ResponseList getSavedSearches() throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createSavedSearchList(get(conf.getRestBaseURL() + ENDPOINT_SAVED_SEARCHES_LIST, + conf.getSigningRestBaseURL() + ENDPOINT_SAVED_SEARCHES_LIST)); + } + + @Override + public ResponseList getSentDirectMessages() throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessageList(get(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_SENT, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_SENT, INCLUDE_ENTITIES)); + } + + @Override + public ResponseList getSentDirectMessages(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessageList(get(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_SENT, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_SENT, + mergeParameters(paging.asPostParameterArray(), INCLUDE_ENTITIES))); + } + + @Override + public SimilarPlaces getSimilarPlaces(final GeoLocation location, final String name, final String containedWithin, + final String streetAddress) throws TwitterException { + final List params = new ArrayList<>(3); + params.add(new HttpParameter("lat", location.getLatitude())); + params.add(new HttpParameter("long", location.getLongitude())); + params.add(new HttpParameter("name", name)); + if (containedWithin != null) { + params.add(new HttpParameter("contained_within", containedWithin)); + } + if (streetAddress != null) { + params.add(new HttpParameter("attribute:street_address", streetAddress)); + } + return factory.createSimilarPlaces(get(conf.getRestBaseURL() + ENDPOINT_GEO_SIMILAR_PLACES, + conf.getSigningRestBaseURL() + ENDPOINT_GEO_SIMILAR_PLACES, + params.toArray(new HttpParameter[params.size()]))); + } + + @Override + public StatusActivitySummary getStatusActivitySummary(final long statusId) throws TwitterException { + return getStatusActivitySummary(statusId, false); + } + + @Override + public StatusActivitySummary getStatusActivitySummary(final long statusId, final boolean includeDescendentReplyCount) + throws TwitterException { + final String endpoint = String.format(Locale.ROOT, "statuses/%d/activity/summary.json", statusId); + final String url = conf.getRestBaseURL() + endpoint; + final String signUrl = conf.getSigningRestBaseURL() + endpoint; + final HttpParameter paramIncludeDescendentReplyCount = new HttpParameter("include_descendent_reply_count", + includeDescendentReplyCount); + return factory.createStatusActivitySummary(get(url, signUrl, paramIncludeDescendentReplyCount)); + } + + @Override + public ResponseList getSuggestedUserCategories() throws TwitterException { + return factory.createCategoryList(get(conf.getRestBaseURL() + ENDPOINT_USERS_SUGGESTIONS, + conf.getSigningRestBaseURL() + ENDPOINT_USERS_SUGGESTIONS)); + } + + @Override + public String getTermsOfService() throws TwitterException { + try { + return get(conf.getRestBaseURL() + ENDPOINT_LEGAL_TOS, conf.getSigningRestBaseURL() + ENDPOINT_LEGAL_TOS) + .asJSONObject().getString("tos"); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + @Override + public PageableResponseList getUserListMembers(final long listId, final CursorPaging paging) + throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS; + return factory.createPagableUserList(get(url, signUrl, mergeParameters(paging.asPostParameterArray(), + new HttpParameter("list_id", listId), INCLUDE_ENTITIES))); + } + + @Override + public PageableResponseList getUserListMembers(final String slug, final long ownerId, + final CursorPaging paging) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS; + return factory.createPagableUserList(get(url, signUrl, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("slug", slug), + new HttpParameter("owner_id", ownerId), INCLUDE_ENTITIES))); + } + + @Override + public PageableResponseList getUserListMembers(final String slug, final String ownerScreenName, + final CursorPaging paging) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERS; + return factory.createPagableUserList(get(url, signUrl, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("slug", slug), + new HttpParameter("owner_screen_name", ownerScreenName), INCLUDE_ENTITIES))); + } + + @Override + public PageableResponseList getUserListMemberships(final long cursor) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createPagableUserListList(get(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERSHIPS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERSHIPS, new HttpParameter("cursor", cursor))); + + } + + @Override + public PageableResponseList getUserListMemberships(final long listMemberId, final long cursor) + throws TwitterException { + return getUserListMemberships(listMemberId, cursor, false); + } + + @Override + public PageableResponseList getUserListMemberships(final long listMemberId, final long cursor, + final boolean filterToOwnedLists) throws TwitterException { + if (filterToOwnedLists) { + ensureAuthorizationEnabled(); + } + return factory.createPagableUserListList(get(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERSHIPS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERSHIPS, new HttpParameter("user_id", listMemberId), + new HttpParameter("cursor", cursor), new HttpParameter("filter_to_owned_lists", filterToOwnedLists))); + } + + @Override + public PageableResponseList getUserListMemberships(final String listMemberScreenName, final long cursor) + throws TwitterException { + return getUserListMemberships(listMemberScreenName, cursor, false); + } + + @Override + public PageableResponseList getUserListMemberships(final String listMemberScreenName, final long cursor, + final boolean filterToOwnedLists) throws TwitterException { + if (filterToOwnedLists) { + ensureAuthorizationEnabled(); + } + return factory.createPagableUserListList(get(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERSHIPS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_MEMBERSHIPS, new HttpParameter("screen_name", + listMemberScreenName), new HttpParameter("cursor", cursor), new HttpParameter( + "filter_to_owned_lists", filterToOwnedLists))); + } + + @Override + public PageableResponseList getUserListOwnerships(final long cursor) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_OWNERSHIPS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_OWNERSHIPS; + return factory.createPagableUserListList(get(url, signUrl, new HttpParameter("cursor", cursor))); + + } + + @Override + public PageableResponseList getUserListOwnerships(final long listMemberId, final long cursor) + throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_OWNERSHIPS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_OWNERSHIPS; + return factory.createPagableUserListList(get(url, signUrl, new HttpParameter("user_id", listMemberId), + new HttpParameter("cursor", cursor))); + } + + @Override + public PageableResponseList getUserListOwnerships(final String listMemberScreenName, final long cursor) + throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_OWNERSHIPS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_OWNERSHIPS; + return factory.createPagableUserListList(get(url, signUrl, new HttpParameter("screen_name", + listMemberScreenName), new HttpParameter("cursor", cursor))); + } + + @Override + public ResponseList getUserLists(final long userId, final boolean reverse) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_LIST; + return factory.createUserListList(get(url, signUrl, + new HttpParameter("user_id", userId), new HttpParameter("reverse", reverse))); + } + + @Override + public ResponseList getUserLists(final String screenName, final boolean reverse) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_LIST; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_LIST; + return factory.createUserListList(get(url, signUrl, + new HttpParameter("screen_name", screenName), new HttpParameter("reverse", reverse))); + } + + @Override + public ResponseList getUserListStatuses(final long listId, final Paging paging) throws TwitterException { + return factory.createStatusList(get( + conf.getRestBaseURL() + ENDPOINT_LISTS_STATUSES, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_STATUSES, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("list_id", listId), INCLUDE_ENTITIES, + INCLUDE_RTS))); + } + + @Override + public ResponseList getUserListStatuses(final String slug, final long ownerId, final Paging paging) + throws TwitterException { + return factory.createStatusList(get( + conf.getRestBaseURL() + ENDPOINT_LISTS_STATUSES, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_STATUSES, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("slug", slug), new HttpParameter( + "owner_id", ownerId), INCLUDE_ENTITIES, INCLUDE_RTS))); + + } + + @Override + public ResponseList getUserListStatuses(final String slug, final String ownerScreenName, final Paging paging) + throws TwitterException { + return factory.createStatusList(get( + conf.getRestBaseURL() + ENDPOINT_LISTS_STATUSES, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_STATUSES, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("slug", slug), new HttpParameter( + "owner_screen_name", ownerScreenName), INCLUDE_ENTITIES, INCLUDE_RTS))); + } + + @Override + public PageableResponseList getUserListSubscribers(final long listId, final CursorPaging paging) + throws TwitterException { + return factory + .createPagableUserList(get( + conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("list_id", listId), + INCLUDE_ENTITIES))); + } + + @Override + public PageableResponseList getUserListSubscribers(final String slug, final long ownerId, + final CursorPaging paging) throws TwitterException { + return factory.createPagableUserList(get( + conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("slug", slug), new HttpParameter( + "owner_id", ownerId), INCLUDE_ENTITIES))); + } + + @Override + public PageableResponseList getUserListSubscribers(final String slug, final String ownerScreenName, + final CursorPaging paging) throws TwitterException { + return factory.createPagableUserList(get( + conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS, + mergeParameters(paging.asPostParameterArray(), new HttpParameter("slug", slug), new HttpParameter( + "owner_screen_name", ownerScreenName), INCLUDE_ENTITIES))); + } + + @Override + public PageableResponseList getUserListSubscriptions(final String listOwnerScreenName, final long cursor) + throws TwitterException { + return factory.createPagableUserListList(get(conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIPTIONS, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIPTIONS, new HttpParameter("screen_name", + listOwnerScreenName), new HttpParameter("cursor", cursor))); + } + + @Override + public ResponseList getUserSuggestions(final String categorySlug) throws TwitterException { + final HttpResponse res = get(conf.getRestBaseURL() + "users/suggestions/" + categorySlug + ".json", + conf.getSigningRestBaseURL() + "users/suggestions/" + categorySlug + ".json"); + return factory.createUserListFromJSONArray_Users(res); + } + + @Override + public ResponseList getUserTimeline() throws TwitterException { + return getUserTimeline(new Paging()); + } + + @Override + public ResponseList getUserTimeline(final long userId) throws TwitterException { + return getUserTimeline(userId, null); + } + + @Override + public ResponseList getUserTimeline(final long userId, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_USER_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_USER_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(INCLUDE_CARDS); + paramsList.add(CARDS_PLATFORM); + paramsList.add(new HttpParameter("user_id", userId)); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public ResponseList getUserTimeline(final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_USER_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_USER_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_MY_RETWEET); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public ResponseList getUserTimeline(final String screenName) throws TwitterException { + return getUserTimeline(screenName, null); + } + + @Override + public ResponseList getUserTimeline(final String screenName, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_USER_TIMELINE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_USER_TIMELINE; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(new HttpParameter("screen_name", screenName)); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, signUrl, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + INCLUDE_ENTITIES.hashCode(); + result = 31 * result + INCLUDE_RTS.hashCode(); + return result; + } + + @Override + public ResponseList lookupFriendships(final long[] ids) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createFriendshipList(get(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_LOOKUP, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_LOOKUP, new HttpParameter("user_id", + InternalStringUtil.join(ids)))); + } + + @Override + public ResponseList lookupFriendships(final String[] screenNames) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createFriendshipList(get(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_LOOKUP, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_LOOKUP, new HttpParameter("screen_name", + InternalStringUtil.join(screenNames)))); + } + + @Override + public ResponseList lookupUsers(final long[] ids) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUserList(get(conf.getRestBaseURL() + ENDPOINT_USERS_LOOKUP, conf.getSigningRestBaseURL() + + ENDPOINT_USERS_LOOKUP, new HttpParameter("user_id", InternalStringUtil.join(ids)), INCLUDE_ENTITIES)); + } + + @Override + public ResponseList lookupUsers(final String[] screenNames) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUserList(get(conf.getRestBaseURL() + ENDPOINT_USERS_LOOKUP, conf.getSigningRestBaseURL() + + ENDPOINT_USERS_LOOKUP, new HttpParameter("screen_name", InternalStringUtil.join(screenNames)), + INCLUDE_ENTITIES)); + } + + @Override + public void removeProfileBannerImage() throws TwitterException { + ensureAuthorizationEnabled(); + post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_REMOVE_PROFILE_BANNER, conf.getSigningRestBaseURL() + + ENDPOINT_ACCOUNT_REMOVE_PROFILE_BANNER); + + } + + @Override + public User reportSpam(final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_USERS_REPORT_SPAM, conf.getSigningRestBaseURL() + + ENDPOINT_USERS_REPORT_SPAM, new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public int reportSpam(final long statusId, final ReportAs reportAs, final boolean blockUser) + throws TwitterException { + ensureAuthorizationEnabled(); + final HttpParameter[] params = {new HttpParameter("status_id", statusId), + new HttpParameter("report_as", reportAs.value()), new HttpParameter("block_user", blockUser)}; + return post(conf.getRestBaseURL() + ENDPOINT_STATUSES_REPORT_SPAM, + conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_REPORT_SPAM, params).getStatusCode(); + } + + @Override + public User reportSpam(final String screenName) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_USERS_REPORT_SPAM, conf.getSigningRestBaseURL() + + ENDPOINT_USERS_REPORT_SPAM, new HttpParameter("screen_name", screenName), INCLUDE_ENTITIES)); + } + + @Override + public Status retweetStatus(final long statusId) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + "statuses/retweet/" + statusId + ".json"; + final String signUrl = conf.getSigningRestBaseURL() + "statuses/retweet/" + statusId + ".json"; + return factory.createStatus(post(url, signUrl, INCLUDE_ENTITIES, INCLUDE_REPLY_COUNT, + INCLUDE_DESCENDENT_REPLY_COUNT)); + } + + @Override + public ResponseList reverseGeoCode(final GeoQuery query) throws TwitterException { + try { + return factory.createPlaceList(get(conf.getRestBaseURL() + ENDPOINT_GEO_REVERSE_GEOCODE, + conf.getSigningRestBaseURL() + ENDPOINT_GEO_REVERSE_GEOCODE, query.asHttpParameterArray())); + } catch (final TwitterException te) { + if (te.getStatusCode() == 404) + return factory.createEmptyResponseList(); + else + throw te; + } + } + + @Override + public QueryResult search(final Query query) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_SEARCH_TWEETS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_SEARCH_TWEETS; + return factory.createQueryResult(get(url, signUrl, + query.asHttpParameterArray(INCLUDE_ENTITIES, INCLUDE_RTS, INCLUDE_REPLY_COUNT, + INCLUDE_DESCENDENT_REPLY_COUNT)), query); + } + + @Override + public ResponseList searchPlaces(final GeoQuery query) throws TwitterException { + return factory.createPlaceList(get(conf.getRestBaseURL() + ENDPOINT_GEO_SEARCH, conf.getSigningRestBaseURL() + + ENDPOINT_GEO_SEARCH, query.asHttpParameterArray())); + } + + @Override + public ResponseList searchUsers(final String query, final int page) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUserList(get(conf.getRestBaseURL() + ENDPOINT_USERS_SEARCH, conf.getSigningRestBaseURL() + + ENDPOINT_USERS_SEARCH, new HttpParameter("q", query), new HttpParameter("per_page", 20), + new HttpParameter("page", page), INCLUDE_ENTITIES)); + } + + @Override + public DirectMessage sendDirectMessage(final long userId, final String text) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessage(post(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, new HttpParameter("user_id", userId), + new HttpParameter("text", text), INCLUDE_ENTITIES)); + } + + @Override + public DirectMessage sendDirectMessage(final long userId, final String text, final long mediaId) + throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessage(post(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, new HttpParameter("user_id", userId), + new HttpParameter("text", text), new HttpParameter("media_id", mediaId), INCLUDE_ENTITIES)); + } + + @Override + public DirectMessage sendDirectMessage(final String screenName, final String text) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessage(post(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, new HttpParameter("screen_name", + screenName), new HttpParameter("text", text), INCLUDE_ENTITIES)); + } + + @Override + public DirectMessage sendDirectMessage(final String screenName, final String text, final long mediaId) + throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createDirectMessage(post(conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, + conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_NEW, new HttpParameter("screen_name", + screenName), new HttpParameter("text", text), new HttpParameter("media_id", mediaId), + INCLUDE_ENTITIES)); + + } + + @Override + public ResponseList showConversation(final long statusId) throws TwitterException { + return showConversation(statusId, null); + } + + @Override + public ResponseList showConversation(final long statusId, final Paging paging) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_CONVERSATION_SHOW; + final String sign_url = conf.getSigningRestBaseURL() + ENDPOINT_CONVERSATION_SHOW; + final List paramsList = new ArrayList<>(); + paramsList.add(INCLUDE_ENTITIES); + paramsList.add(INCLUDE_REPLY_COUNT); + paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT); + paramsList.add(INCLUDE_MY_RETWEET); + paramsList.add(INCLUDE_CARDS); + paramsList.add(CARDS_PLATFORM); + paramsList.add(new HttpParameter("id", statusId)); + if (paging != null) { + paramsList.addAll(paging.asPostParameterList()); + } + return factory.createStatusList(get(url, sign_url, paramsList.toArray(new HttpParameter[paramsList.size()]))); + } + + @Override + public DirectMessage showDirectMessage(final long id) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_SHOW; + final String sign_url = conf.getSigningRestBaseURL() + ENDPOINT_DIRECT_MESSAGES_SHOW; + return factory.createDirectMessage(get(url, sign_url, new HttpParameter("id", id), INCLUDE_ENTITIES)); + } + + @Override + public Relationship showFriendship(final long sourceId, final long targetId) throws TwitterException { + return factory.createRelationship(get(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_SHOW, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_SHOW, new HttpParameter("source_id", sourceId), + new HttpParameter("target_id", targetId))); + } + + @Override + public Relationship showFriendship(final String sourceScreenName, final String targetScreenName) + throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_SHOW; + return factory.createRelationship(get(url, signUrl, getParameterArray("source_screen_name", sourceScreenName, "target_screen_name", targetScreenName))); + } + + @Override + public SavedSearch showSavedSearch(final int id) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + "saved_searches/show/" + id + ".json"; + final String signUrl = conf.getSigningRestBaseURL() + "saved_searches/show/" + id + ".json"; + return factory.createSavedSearch(get(url, signUrl)); + } + + @Override + public Status showStatus(final long statusId) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_SHOW; + final HttpParameter paramStatus = new HttpParameter("id", statusId); + return factory.createStatus(get(url, signUrl, paramStatus, INCLUDE_ENTITIES, + INCLUDE_MY_RETWEET, INCLUDE_REPLY_COUNT, INCLUDE_DESCENDENT_REPLY_COUNT, INCLUDE_CARDS, + CARDS_PLATFORM)); + } + + @Override + public TranslationResult showTranslation(final long statusId, final String dest) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_TRANSLATIONS_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_TRANSLATIONS_SHOW; + final HttpParameter paramStatus = new HttpParameter("id", statusId); + final HttpParameter paramDest = new HttpParameter("dest", dest); + return factory.createTranslationResult(get(url, signUrl, paramStatus, paramDest)); + } + + @Override + public User showUser(final long userId) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_USERS_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_USERS_SHOW; + return factory.createUser(get(url, signUrl, new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public User showUser(final String screenName) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_USERS_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_USERS_SHOW; + return factory.createUser(get(url, signUrl, new HttpParameter("screen_name", screenName), INCLUDE_ENTITIES)); + } + + @Override + public UserList showUserList(final long listId) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SHOW; + return factory.createAUserList(get(url, signUrl, new HttpParameter("list_id", listId))); + } + + @Override + public UserList showUserList(final String slug, final long ownerId) throws TwitterException { + final String url = conf.getRestBaseURL() + ENDPOINT_LISTS_SHOW; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SHOW; + return factory.createAUserList(get(url, signUrl, new HttpParameter("slug", slug), new HttpParameter("owner_id", ownerId))); + } + + @Override + public UserList showUserList(final String slug, final String ownerScreenName) throws TwitterException { + return factory.createAUserList(get(conf.getRestBaseURL() + ENDPOINT_LISTS_SHOW, conf.getSigningRestBaseURL() + + ENDPOINT_LISTS_SHOW, new HttpParameter("slug", slug), new HttpParameter("owner_screen_name", + ownerScreenName))); + } + + @Override + public User showUserListMembership(final long listId, final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(get(conf.getRestBaseURL() + ENDPOINT_LISTS_MEMBERS_SHOW, conf.getSigningRestBaseURL() + + ENDPOINT_LISTS_MEMBERS_SHOW, new HttpParameter("list_id", listId), new HttpParameter("user_id", + userId), INCLUDE_ENTITIES)); + } + + @Override + public User showUserListSubscription(final long listId, final long userId) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(get(conf.getRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS_SHOW, + conf.getSigningRestBaseURL() + ENDPOINT_LISTS_SUBSCRIBERS_SHOW, new HttpParameter("list_id", listId), + new HttpParameter("user_id", userId), INCLUDE_ENTITIES)); + } + + @Override + public String toString() { + return "TwitterImpl{" + "INCLUDE_ENTITIES=" + INCLUDE_ENTITIES + ", INCLUDE_RTS=" + INCLUDE_RTS + '}'; + } + + @Override + public AccountSettings updateAccountSettings(final SettingsUpdate settingsUpdate) throws TwitterException { + ensureAuthorizationEnabled(); + final List params = new ArrayList<>(); + settingsUpdate.addToHttpParameterList(params); + params.add(INCLUDE_ENTITIES); + final String url = conf.getRestBaseURL() + ENDPOINT_ACCOUNT_SETTINGS; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_SETTINGS; + return factory.createAccountSettings(post(url, signUrl, params.toArray(new HttpParameter[params.size()]))); + } + + @Override + public Relationship updateFriendship(final long userId, final boolean enableDeviceNotification, + final boolean retweets) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createRelationship(post(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_UPDATE, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_UPDATE, new HttpParameter("user_id", userId), + new HttpParameter("device", enableDeviceNotification), new HttpParameter("retweets", + enableDeviceNotification))); + } + + @Override + public Relationship updateFriendship(final String screenName, final boolean enableDeviceNotification, + final boolean retweets) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createRelationship(post(conf.getRestBaseURL() + ENDPOINT_FRIENDSHIPS_UPDATE, + conf.getSigningRestBaseURL() + ENDPOINT_FRIENDSHIPS_UPDATE, + new HttpParameter("screen_name", screenName), new HttpParameter("device", enableDeviceNotification), + new HttpParameter("retweets", enableDeviceNotification))); + } + + @Override + public User updateProfile(final String name, final String url, final String location, final String description) + throws TwitterException { + ensureAuthorizationEnabled(); + final ArrayList params = new ArrayList<>(); + addParameterToList(params, "name", name); + addParameterToList(params, "url", url); + addParameterToList(params, "location", location); + addParameterToList(params, "description", description); + params.add(INCLUDE_ENTITIES); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE, + params.toArray(new HttpParameter[params.size()]))); + } + + @Override + public User updateProfileBackgroundImage(final File image, final boolean tile) throws TwitterException { + ensureAuthorizationEnabled(); + checkFileValidity(image); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BACKGROUND_IMAGE, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BACKGROUND_IMAGE, new HttpParameter( + "image", image), new HttpParameter("tile", tile), INCLUDE_ENTITIES)); + } + + @Override + public User updateProfileBackgroundImage(final InputStream image, final boolean tile) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BACKGROUND_IMAGE, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BACKGROUND_IMAGE, new HttpParameter( + "image", "image", image), new HttpParameter("tile", tile), INCLUDE_ENTITIES)); + } + + @Override + public void updateProfileBannerImage(final File banner) throws TwitterException { + ensureAuthorizationEnabled(); + checkFileValidity(banner); + post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, conf.getSigningRestBaseURL() + + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, new HttpParameter("banner", banner)); + } + + @Override + public void updateProfileBannerImage(final File banner, final int width, final int height, final int offsetLeft, + final int offsetTop) throws TwitterException { + ensureAuthorizationEnabled(); + checkFileValidity(banner); + final List params = new ArrayList<>(5); + addParameterToList(params, "width", width); + addParameterToList(params, "height", height); + addParameterToList(params, "offset_left", offsetLeft); + addParameterToList(params, "offset_top", offsetTop); + params.add(new HttpParameter("banner", banner)); + post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, conf.getSigningRestBaseURL() + + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, params.toArray(new HttpParameter[params.size()])); + + } + + @Override + public void updateProfileBannerImage(final InputStream banner) throws TwitterException { + ensureAuthorizationEnabled(); + post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, conf.getSigningRestBaseURL() + + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, new HttpParameter("banner", "banner", banner)); + } + + @Override + public void updateProfileBannerImage(final InputStream banner, final int width, final int height, + final int offsetLeft, final int offsetTop) throws TwitterException { + ensureAuthorizationEnabled(); + final List params = new ArrayList<>(5); + addParameterToList(params, "width", width); + addParameterToList(params, "height", height); + addParameterToList(params, "offset_left", offsetLeft); + addParameterToList(params, "offset_top", offsetTop); + params.add(new HttpParameter("banner", "banner", banner)); + post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, conf.getSigningRestBaseURL() + + ENDPOINT_ACCOUNT_UPDATE_PROFILE_BANNER, params.toArray(new HttpParameter[params.size()])); + } + + @Override + public User updateProfileColors(final String profileBackgroundColor, final String profileTextColor, + final String profileLinkColor, final String profileSidebarFillColor, final String profileSidebarBorderColor) + throws TwitterException { + ensureAuthorizationEnabled(); + final List params = new ArrayList<>(6); + addParameterToList(params, "profile_background_color", profileBackgroundColor); + addParameterToList(params, "profile_text_color", profileTextColor); + addParameterToList(params, "profile_link_color", profileLinkColor); + addParameterToList(params, "profile_sidebar_fill_color", profileSidebarFillColor); + addParameterToList(params, "profile_sidebar_border_color", profileSidebarBorderColor); + params.add(INCLUDE_ENTITIES); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_COLORS, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_COLORS, + params.toArray(new HttpParameter[params.size()]))); + } + + @Override + public User updateProfileImage(final File image) throws TwitterException { + checkFileValidity(image); + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_IMAGE, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_IMAGE, + new HttpParameter("image", image), INCLUDE_ENTITIES)); + } + + @Override + public User updateProfileImage(final InputStream image) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createUser(post(conf.getRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_IMAGE, + conf.getSigningRestBaseURL() + ENDPOINT_ACCOUNT_UPDATE_PROFILE_IMAGE, new HttpParameter("image", + "image", image), INCLUDE_ENTITIES)); + } + + @Override + public Status updateStatus(final StatusUpdate status) throws TwitterException { + ensureAuthorizationEnabled(); + final String url = conf.getRestBaseURL() + ENDPOINT_STATUSES_UPDATE; + final String signUrl = conf.getSigningRestBaseURL() + ENDPOINT_STATUSES_UPDATE; + return factory.createStatus(post(url, signUrl, status.asHttpParameterArray(INCLUDE_ENTITIES))); + } + + @Override + public Status updateStatus(final String status) throws TwitterException { + ensureAuthorizationEnabled(); + return factory.createStatus(post(conf.getRestBaseURL() + ENDPOINT_STATUSES_UPDATE, conf.getSigningRestBaseURL() + + ENDPOINT_STATUSES_UPDATE, new HttpParameter("status", status), INCLUDE_ENTITIES)); + } + + @Override + public UserList updateUserList(final long listId, final String newListName, final boolean isPublicList, + final String newDescription) throws TwitterException { + ensureAuthorizationEnabled(); + final List httpParams = new ArrayList<>(); + httpParams.add(new HttpParameter("list_id", listId)); + if (newListName != null) { + httpParams.add(new HttpParameter("name", newListName)); + } + httpParams.add(new HttpParameter("mode", isPublicList ? "public" : "private")); + if (newDescription != null) { + httpParams.add(new HttpParameter("description", newDescription)); + } + return factory.createAUserList(post(conf.getRestBaseURL() + ENDPOINT_LISTS_UPDATE, conf.getSigningRestBaseURL() + + ENDPOINT_LISTS_UPDATE, httpParams.toArray(new HttpParameter[httpParams.size()]))); + } + + @Override + public MediaUploadResponse uploadMedia(final File file) throws TwitterException { + final String url = conf.getUploadBaseURL() + ENDPOINT_MEDIA_UPLOAD; + final String signUrl = conf.getSigningUploadBaseURL() + ENDPOINT_MEDIA_UPLOAD; + return factory.createMediaUploadResponse(post(url, signUrl, new HttpParameter("media", file))); + } + + @Override + public MediaUploadResponse uploadMedia(final String fileName, final InputStream fileBody, final String fileType) + throws TwitterException { + final String url = conf.getUploadBaseURL() + ENDPOINT_MEDIA_UPLOAD; + final String signUrl = conf.getSigningUploadBaseURL() + ENDPOINT_MEDIA_UPLOAD; + return factory.createMediaUploadResponse(post(url, signUrl, new HttpParameter("media", fileName, fileBody, + fileType))); + } + + @Override + public User verifyCredentials() throws TwitterException { + return super.fillInIDAndScreenName(); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterResponse.java b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterResponse.java new file mode 100644 index 00000000..7fca1eca --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/TwitterResponse.java @@ -0,0 +1,59 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * Super interface of Twitter Response data interfaces which indicates that rate + * limit status is avaialble. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see DirectMessage + * @see twitter4j.Status + * @see User + */ +public interface TwitterResponse extends Serializable { + int NONE = 0; + + int READ = 1; + + int READ_WRITE = 2; + int READ_WRITE_DIRECTMESSAGES = 3; + + /** + * @return application permission model + * @see Application + * Permission Model FAQ - How do we know what the access level of a + * user token is? + * @since Twitter4J 2.2.3 + */ + int getAccessLevel(); + + /** + * Returns the current rate limit status if available. + * + * @return current rate limit status + * @since Twitter4J 2.1.0 + */ + RateLimitStatus getRateLimitStatus(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/URLEntity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/URLEntity.java new file mode 100644 index 00000000..69da6413 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/URLEntity.java @@ -0,0 +1,68 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.net.URL; + +/** + * A data interface representing one single URL entity. + * + * @author Mocel - mocel at guma.jp + * @since Twitter4J 2.1.9 + */ +public interface URLEntity extends Serializable { + + /** + * Returns the display URL if mentioned URL is shorten. + * + * @return the display URL if mentioned URL is shorten, or null if no + * shorten URL was mentioned. + */ + String getDisplayURL(); + + /** + * Returns the index of the end character of the URL mentioned in the tweet. + * + * @return the index of the end character of the URL mentioned in the tweet + */ + int getEnd(); + + /** + * Returns the expanded URL if mentioned URL is shorten. + * + * @return the expanded URL if mentioned URL is shorten, or null if no + * shorten URL was mentioned. + */ + String getExpandedURL(); + + /** + * Returns the index of the start character of the URL mentioned in the + * tweet. + * + * @return the index of the start character of the URL mentioned in the + * tweet + */ + int getStart(); + + /** + * Returns the URL mentioned in the tweet. + * + * @return the mentioned URL + */ + String getURL(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/User.java b/firetweet.component.twitter4j/src/main/java/twitter4j/User.java new file mode 100644 index 00000000..e4cbbf98 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/User.java @@ -0,0 +1,204 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.net.URL; +import java.util.Date; + +/** + * A data interface representing Basic user information element + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface User extends Comparable, TwitterResponse, Serializable { + Date getCreatedAt(); + + /** + * Returns the description of the user + * + * @return the description of the user + */ + String getDescription(); + + URLEntity[] getDescriptionEntities(); + + int getFavouritesCount(); + + /** + * Returns the number of followers + * + * @return the number of followers + * @since Twitter4J 1.0.4 + */ + int getFollowersCount(); + + int getFriendsCount(); + + /** + * Returns the id of the user + * + * @return the id of the user + */ + long getId(); + + /** + * Returns the preferred language of the user + * + * @return the preferred language of the user + * @since Twitter4J 2.1.2 + */ + String getLang(); + + /** + * Returns the number of public lists the user is listed on, or -1 if the + * count is unavailable. + * + * @return the number of public lists the user is listed on. + * @since Twitter4J 2.1.4 + */ + int getListedCount(); + + /** + * Returns the location of the user + * + * @return the location of the user + */ + String getLocation(); + + /** + * Returns the name of the user + * + * @return the name of the user + */ + String getName(); + + String getProfileBackgroundColor(); + + String getProfileBackgroundImageUrl(); + + String getProfileBackgroundImageUrlHttps(); + + String getProfileBannerImageUrl(); + + /** + * Returns the profile image url of the user + * + * @return the profile image url of the user + */ + String getProfileImageURL(); + + /** + * Returns the profile image url of the user, served over SSL + * + * @return the profile image url of the user, served over SSL + */ + String getProfileImageUrlHttps(); + + String getProfileLinkColor(); + + String getProfileSidebarBorderColor(); + + String getProfileSidebarFillColor(); + + String getProfileTextColor(); + + /** + * Returns the screen name of the user + * + * @return the screen name of the user + */ + String getScreenName(); + + /** + * Returns the current status of the user
+ * This can be null if the instance if from Status.getUser(). + * + * @return current status of the user + * @since Twitter4J 2.1.1 + */ + Status getStatus(); + + int getStatusesCount(); + + String getTimeZone(); + + /** + * Returns the url of the user + * + * @return the url of the user + */ + String getURL(); + + URLEntity[] getURLEntities(); + + int getUtcOffset(); + + /** + * Tests if the user is enabling contributors + * + * @return if the user is enabling contributors + * @since Twitter4J 2.1.2 + */ + boolean isContributorsEnabled(); + + boolean isDefaultProfileImage(); + + boolean isFollowing(); + + /** + * Returns true if the authenticating user has requested to follow this + * user, otherwise false. + * + * @return true if the authenticating user has requested to follow this + * user. + * @since Twitter4J 2.1.4 + */ + boolean isFollowRequestSent(); + + /** + * @return the user is enabling geo location + * @since Twitter4J 2.0.10 + */ + boolean isGeoEnabled(); + + boolean isProfileBackgroundTiled(); + + boolean isProfileUseBackgroundImage(); + + /** + * Test if the user status is protected + * + * @return true if the user status is protected + */ + boolean isProtected(); + + boolean isShowAllInlineMedia(); + + /** + * @return returns true if the user is a translator + * @since Twitter4J 2.1.9 + */ + boolean isTranslator(); + + /** + * @return returns true if the user is a verified celebrity + * @since Twitter4J 2.0.10 + */ + boolean isVerified(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/UserList.java b/firetweet.component.twitter4j/src/main/java/twitter4j/UserList.java new file mode 100644 index 00000000..f71c977d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/UserList.java @@ -0,0 +1,104 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; +import java.net.URI; + +/** + * A data interface representing Basic list information element + * + * @author Dan Checkoway - dcheckoway at gmail.com + */ +public interface UserList extends Comparable, TwitterResponse, Serializable { + /** + * Returns the description of the list + * + * @return the description of the list + */ + String getDescription(); + + /** + * Returns the full name of the list + * + * @return the full name of the list + */ + String getFullName(); + + /** + * Returns the id of the list + * + * @return the id of the list + */ + long getId(); + + /** + * Returns the member count of the list + * + * @return the member count of the list + */ + int getMemberCount(); + + /** + * Returns the name of the list + * + * @return the name of the list + */ + String getName(); + + /** + * Returns the slug of the list + * + * @return the slug of the list + */ + String getSlug(); + + /** + * Returns the subscriber count of the list + * + * @return the subscriber count of the list + */ + int getSubscriberCount(); + + /** + * Returns the uri of the list + * + * @return the uri of the list + */ + URI getURI(); + + /** + * Returns the user of the list + * + * @return the user of the list + */ + User getUser(); + + /** + * Returns if the authenticated user is following the list + * + * @return if the authenticated user is following the list + */ + boolean isFollowing(); + + /** + * tests if the list is public + * + * @return if the list is public + */ + boolean isPublic(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/UserMentionEntity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/UserMentionEntity.java new file mode 100644 index 00000000..f911ab8c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/UserMentionEntity.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +import java.io.Serializable; + +/** + * A data interface representing one single user mention entity. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +public interface UserMentionEntity extends Serializable { + /** + * Returns the index of the end character of the user mention. + * + * @return the index of the end character of the user mention + */ + int getEnd(); + + /** + * Returns the user id mentioned in the status. + * + * @return the user id mentioned in the status + */ + long getId(); + + /** + * Returns the name mentioned in the status. + * + * @return the name mentioned in the status + */ + String getName(); + + /** + * Returns the screen name mentioned in the status. + * + * @return the screen name mentioned in the status + */ + String getScreenName(); + + /** + * Returns the index of the start character of the user mention. + * + * @return the index of the start character of the user mention + */ + int getStart(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/Version.java b/firetweet.component.twitter4j/src/main/java/twitter4j/Version.java new file mode 100644 index 00000000..f22afa3e --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/Version.java @@ -0,0 +1,42 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class Version { + private static final String VERSION = "3.0.3"; + private static final String TITLE = "Twitter4J"; + + private Version() { + throw new AssertionError(); + } + + public static String getVersion() { + return VERSION; + } + + /** + * prints the version string + * + * @param args will be just ignored. + */ + public static void main(final String[] args) { + System.out.println(TITLE + " " + VERSION); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/DirectMessagesResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/DirectMessagesResources.java new file mode 100644 index 00000000..de173f1b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/DirectMessagesResources.java @@ -0,0 +1,151 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.api; + +import twitter4j.DirectMessage; +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface DirectMessagesResources { + /** + * Destroys the direct message specified in the required ID parameter. The + * authenticating user must be the recipient of the specified direct + * message.
+ * This method calls http://api.twitter.com/1.1/direct_messages/destroy + * + * @param id the ID of the direct message to destroy + * @return the deleted direct message + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * direct_messages/destroy/:id | Twitter Developers + * @since Twitter4J 2.0.1 + */ + DirectMessage destroyDirectMessage(long id) throws TwitterException; + + /** + * Returns a list of the direct messages sent to the authenticating user.
+ * This method calls http://api.twitter.com/1.1/direct_messages + * + * @return List + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * direct_messages | Twitter Developers + */ + ResponseList getDirectMessages() throws TwitterException; + + /** + * Returns a list of the direct messages sent to the authenticating user.
+ * This method calls http://api.twitter.com/1.1/direct_messages + * + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return List + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * direct_messages | Twitter Developers + */ + ResponseList getDirectMessages(Paging paging) throws TwitterException; + + /** + * Returns a list of the direct messages sent by the authenticating user.
+ * This method calls http://api.twitter.com/1.1/direct_messages/sent + * + * @return List + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * direct_messages/sent | Twitter Developers + */ + ResponseList getSentDirectMessages() throws TwitterException; + + /** + * Returns a list of the direct messages sent by the authenticating user.
+ * This method calls http://api.twitter.com/1.1/direct_messages/sent + * + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return List + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * direct_messages/sent | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getSentDirectMessages(Paging paging) throws TwitterException; + + DirectMessage sendDirectMessage(long userId, String text) throws TwitterException; + + /** + * Sends a new direct message to the specified user from the authenticating + * user. Requires both the user and text parameters below. The text will be + * trimmed if the length of the text is exceeding 140 characters.
+ * This method calls http://api.twitter.com/1.1/direct_messages/new + * + * @param userId the screen name of the user to whom send the direct message + * @param text The text of your direct message. + * @return DirectMessage + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * direct_messages/new | Twitter Developers + * @since Twitter4j 2.1.0 + */ + DirectMessage sendDirectMessage(long userId, String text, long mediaId) throws TwitterException; + + DirectMessage sendDirectMessage(String screenName, String text) throws TwitterException; + + /** + * Sends a new direct message to the specified user from the authenticating + * user. Requires both the user and text parameters below. The text will be + * trimmed if the length of the text is exceeding 140 characters.
+ * This method calls http://api.twitter.com/1.1/direct_messages/new + * + * @param screenName the screen name of the user to whom send the direct + * message + * @param text The text of your direct message. + * @return DirectMessage + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * direct_messages/new | Twitter Developers + */ + DirectMessage sendDirectMessage(String screenName, String text, long mediaId) throws TwitterException; + + /** + * Returns a single direct message, specified by an id parameter.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls + * http://api.twitter.com/1.1/direct_messages/show/:id.json + * + * @param id message id + * @return DirectMessage + * @throws TwitterException when Twitter service or network is unavailable + * @see #newtwitter + * and the API - Twitter API Announcements | Google Group + * @since Twitter4J 2.1.9 + */ + DirectMessage showDirectMessage(long id) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/FavoritesResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/FavoritesResources.java new file mode 100644 index 00000000..1c0d4e23 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/FavoritesResources.java @@ -0,0 +1,151 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface FavoritesResources { + /** + * Favorites the status specified in the ID parameter as the authenticating + * user. Returns the favorite status when successful.
+ * This method calls http://api.twitter.com/1.1/favorites/create/[id].json + * + * @param id the ID of the status to favorite + * @return Status + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * favorites/create/:id | Twitter Developers + */ + Status createFavorite(long id) throws TwitterException; + + /** + * Un-favorites the status specified in the ID parameter as the + * authenticating user. Returns the un-favorited status in the requested + * format when successful.
+ * This method calls http://api.twitter.com/1.1/favorites/destroy/[id].json + * + * @param id the ID of the status to un-favorite + * @return Status + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * favorites/destroy/:id | Twitter Developers + */ + Status destroyFavorite(long id) throws TwitterException; + + /** + * Returns the 20 most recent favorite statuses for the authenticating user + * or user specified by the ID parameter in the requested format.
+ * This method calls http://api.twitter.com/1.1/favorites/list.json + * + * @return ResponseList<Status> + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * favorites | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getFavorites() throws TwitterException; + + /** + * Returns the 20 most recent favorite statuses for the authenticating user + * or user specified by the ID parameter in the requested format. + * + * @param userId the ID of the user for whom to request a list of favorite + * statuses + * @return ResponseList<Status> + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * favorites | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getFavorites(long userId) throws TwitterException; + + /** + * Returns the 20 most recent favorite statuses for the authenticating user + * or user specified by the ID parameter in the requested format. + * + * @param userId the ID of the user for whom to request a list of favorite + * statuses + * @param paging controls pagination. Supports sinceId and page parameters. + * @return ResponseList<Status> + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * favorites | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getFavorites(long userId, Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent favorite statuses for the authenticating user + * or user specified by the ID parameter in the requested format.
+ * This method calls http://api.twitter.com/1.1/favorites/list.json + * + * @param paging controls pagination. Supports sinceId and page parameters. + * @return ResponseList<Status> + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * favorites | Twitter Developers + * @since Twitter4J 2.2.5 + */ + ResponseList getFavorites(Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent favorite statuses for the authenticating user + * or user specified by the ID parameter in the requested format. + * + * @param screenName the screen name of the user for whom to request a list + * of favorite statuses + * @return ResponseList<Status> + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * favorites | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getFavorites(String screenName) throws TwitterException; + + /** + * Returns the 20 most recent favorite statuses for the authenticating user + * or user specified by the ID parameter in the requested format.
+ * This method calls http://api.twitter.com/1.1/favorites/[id].json + * + * @param screenName the screen name of the user for whom to request a list + * of favorite statuses + * @param paging controls pagination. Supports sinceId and page parameters. + * @return ResponseList<Status> + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * favorites | Twitter Developers + * @since Twitter4J 2.2.5 + */ + ResponseList getFavorites(String screenName, Paging paging) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/FriendsFollowersResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/FriendsFollowersResources.java new file mode 100644 index 00000000..67aa22b9 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/FriendsFollowersResources.java @@ -0,0 +1,311 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.CursorPaging; +import twitter4j.Friendship; +import twitter4j.IDs; +import twitter4j.PageableResponseList; +import twitter4j.Relationship; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.User; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface FriendsFollowersResources { + + /** + * Allows the authenticating users to follow the user specified in the ID + * parameter.
+ * Returns the befriended user in the requested format when successful. + * Returns a string describing the failure condition when unsuccessful. If + * you are already friends with the user an HTTP 403 will be returned.
+ * This method calls http://api.twitter.com/1.1/friendships/create/[id].json + * + * @param userId the ID of the user to be befriended + * @return the befriended user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * friendships/create | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User createFriendship(long userId) throws TwitterException; + + /** + * Allows the authenticating users to follow the user specified in the ID + * parameter.
+ * Returns the befriended user in the requested format when successful. + * Returns a string describing the failure condition when unsuccessful. If + * you are already friends with the user an HTTP 403 will be returned.
+ * This method calls http://api.twitter.com/1.1/friendships/create/[id].json + * + * @param userId the ID of the user to be befriended + * @param follow Enable notifications for the target user in addition to + * becoming friends. + * @return the befriended user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * friendships/create | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User createFriendship(long userId, boolean follow) throws TwitterException; + + /** + * Allows the authenticating users to follow the user specified in the ID + * parameter.
+ * Returns the befriended user in the requested format when successful. + * Returns a string describing the failure condition when unsuccessful. If + * you are already friends with the user an HTTP 403 will be returned.
+ * This method calls http://api.twitter.com/1.1/friendships/create/[id].json + * + * @param screenName the screen name of the user to be befriended + * @return the befriended user + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see POST + * friendships/create | Twitter Developers + * @since Twitter4J 2.0.1 + */ + User createFriendship(String screenName) throws TwitterException; + + /** + * Allows the authenticating users to follow the user specified in the ID + * parameter.
+ * Returns the befriended user in the requested format when successful. + * Returns a string describing the failure condition when unsuccessful. If + * you are already friends with the user an HTTP 403 will be returned.
+ * This method calls http://api.twitter.com/1.1/friendships/create/[id].json + * + * @param screenName the screen name of the user to be befriended + * @param follow Enable notifications for the target user in addition to + * becoming friends. + * @return the befriended user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * friendships/create | Twitter Developers + * @since Twitter4J 2.0.2 + */ + User createFriendship(String screenName, boolean follow) throws TwitterException; + + /** + * Allows the authenticating users to unfollow the user specified in the ID + * parameter.
+ * Returns the unfollowed user in the requested format when successful. + * Returns a string describing the failure condition when unsuccessful.
+ * This method calls + * http://api.twitter.com/1.1/friendships/destroy/[id].json + * + * @param userId the ID of the user for whom to request a list of friends + * @return User + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * friendships/destroy | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User destroyFriendship(long userId) throws TwitterException; + + /** + * Allows the authenticating users to unfollow the user specified in the ID + * parameter.
+ * Returns the unfollowed user in the requested format when successful. + * Returns a string describing the failure condition when unsuccessful.
+ * This method calls + * http://api.twitter.com/1.1/friendships/destroy/[id].json + * + * @param screenName the screen name of the user for whom to request a list + * of friends + * @return User + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * friendships/destroy | Twitter Developers + * @since Twitter4J 2.0.1 + */ + User destroyFriendship(String screenName) throws TwitterException; + + IDs getFollowersIDs(CursorPaging paging) throws TwitterException; + + IDs getFollowersIDs(long userId, CursorPaging paging) throws TwitterException; + + IDs getFollowersIDs(String screenName, CursorPaging paging) throws TwitterException; + + PageableResponseList getFollowersList(CursorPaging paging) throws TwitterException; + + PageableResponseList getFollowersList(long userId, CursorPaging paging) throws TwitterException; + + PageableResponseList getFollowersList(String screenName, CursorPaging paging) throws TwitterException; + + IDs getFriendsIDs(CursorPaging paging) throws TwitterException; + + IDs getFriendsIDs(long userId, CursorPaging paging) throws TwitterException; + + IDs getFriendsIDs(String screenName, CursorPaging paging) throws TwitterException; + + PageableResponseList getFriendsList(CursorPaging paging) throws TwitterException; + + PageableResponseList getFriendsList(long userId, CursorPaging paging) throws TwitterException; + + PageableResponseList getFriendsList(String screenName, CursorPaging paging) throws TwitterException; + + /** + * Returns an array of numeric IDs for every user who has a pending request + * to follow the authenticating user.
+ * This method calls http://api.twitter.com/1.1/friendships/incoming.json + * + * @param paging Breaks the results into pages. A single page contains 5000 + * identifiers. Provide a value of -1 to begin paging. + * @return an array of numeric IDs for every user who has a pending request + * to follow the authenticating user. + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * friendships/incoming | Twitter Developers + * @since Twitter4J 2.1.2 + */ + IDs getIncomingFriendships(CursorPaging paging) throws TwitterException; + + /** + * Returns an array of numeric IDs for every protected user for whom the + * authenticating user has a pending follow request.
+ * This method calls http://api.twitter.com/1.1/friendships/outgoing.json + * + * @param paging Breaks the results into pages. A single page contains 5000 + * identifiers. Provide a value of -1 to begin paging. + * @return an array of numeric IDs for every protected user for whom the + * authenticating user has a pending follow request. + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * friendships/outgoing | Twitter Developers + * @since Twitter4J 2.1.2 + */ + IDs getOutgoingFriendships(CursorPaging paging) throws TwitterException; + + /** + * Returns the relationship of the authenticating user to the specified + * users.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls http://api.twitter.com/1.1/friendships/lookup.json + * + * @param ids array of the ids to lookup + * @return list of Relationships + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see #newtwitter + * and the API - Twitter API Announcements | Google Group + * @since Twitter4J 2.1.9 + */ + ResponseList lookupFriendships(long[] ids) throws TwitterException; + + /** + * Returns the relationship of the authenticating user to the specified + * users.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls http://api.twitter.com/1.1/friendships/lookup.json + * + * @param screenNames array of the screen names to lookup + * @return list of Relationships + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see #newtwitter + * and the API - Twitter API Announcements | Google Group + * @since Twitter4J 2.1.9 + */ + ResponseList lookupFriendships(String[] screenNames) throws TwitterException; + + /** + * Returns detailed information about the relationship between two users.
+ * This method calls http://api.twitter.com/1.1/friendships/show.json + * + * @param sourceId the ID of the source user + * @param targetId the ID of the target user + * @return Relationship + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * friendships/show | Twitter Developers + * @since Twitter4J 2.1.0 + */ + Relationship showFriendship(long sourceId, long targetId) throws TwitterException; + + /** + * Returns detailed information about the relationship between two users.
+ * This method calls http://api.twitter.com/1.1/friendships/show.json + * + * @param sourceScreenName the screen name of the source user + * @param targetScreenName the screen name of the target user + * @return Relationship + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * friendships/show | Twitter Developers + * @since Twitter4J 2.1.0 + */ + Relationship showFriendship(String sourceScreenName, String targetScreenName) throws TwitterException; + + /** + * Allows you to enable or disable retweets and device notifications from + * the specified user.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls http://api.twitter.com/1.1/friendships/update.json + * + * @param userId user id to update + * @param enableDeviceNotification set true to enable device notification + * @param retweets set true to enable retweets + * @return Relationship + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see #newtwitter + * and the API - Twitter API Announcements | Google Group + * @since Twitter4J 2.1.9 + */ + Relationship updateFriendship(long userId, boolean enableDeviceNotification, boolean retweets) + throws TwitterException; + + /** + * Allows you to enable or disable retweets and device notifications from + * the specified user.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls http://api.twitter.com/1.1/friendships/update.json + * + * @param screenName screen name to update + * @param enableDeviceNotification set true to enable device notification + * @param retweets set true to enable retweets + * @return Relationship + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see #newtwitter + * and the API - Twitter API Announcements | Google Group + * @since Twitter4J 2.1.9 + */ + Relationship updateFriendship(String screenName, boolean enableDeviceNotification, boolean retweets) + throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/HelpResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/HelpResources.java new file mode 100644 index 00000000..dfcfbb4f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/HelpResources.java @@ -0,0 +1,166 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import java.util.Map; + +import twitter4j.RateLimitStatus; +import twitter4j.ResponseList; +import twitter4j.TwitterAPIConfiguration; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface HelpResources { + /** + * Returns the current configuration used by Twitter including twitter.com + * slugs which are not usernames, maximum photo resolutions, and t.co URL + * lengths.
It is recommended applications request this endpoint when + * they are loaded, but no more than once a day. + * + * @return configuration + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * help/configuration | Twitter Developers + * @since Twitter4J 2.2.3 + */ + TwitterAPIConfiguration getAPIConfiguration() throws TwitterException; + + /** + * Returns the list of languages supported by Twitter along with their ISO + * 639-1 code. The ISO 639-1 code is the two letter value to use if you + * include lang with any of your requests. + * + * @return list of languages supported by Twitter + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * help/languages | Twitter Developers + * @since Twitter4J 2.2.3 + */ + ResponseList getLanguages() throws TwitterException; + + /** + * Returns Twitter's Privacy Policy.
+ * This method calls http://api.twitter.com/1.1/legal/privacy.json + * + * @return privacy policy + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * legal/privacy | Twitter Developers + * @since Twitter4J 2.1.7 + */ + String getPrivacyPolicy() throws TwitterException; + + /** + * Returns the current rate limits for methods belonging to the specified + * resource families.
+ * Each 1.1 API resource belongs to a "resource family" which is indicated + * in its method documentation. You can typically determine a method's + * resource family from the first component of the path after the resource + * version.
+ * This method responds with a map of methods belonging to the families + * specified by the resources parameter, the current remaining uses for each + * of those resources within the current rate limiting window, and its + * expiration time in epoch time. It also includes a rate_limit_context + * field that indicates the current access token context.
+ * You may also issue requests to this method without any parameters to + * receive a map of all rate limited GET methods. If your application only + * uses a few of methods, please explicitly provide a resources parameter + * with the specified resource families you work with.
+ * Read more about REST API Rate Limiting in v1.1 and review the limits.
+ *
+ * This method calls + * http://api.twitter.com/1.1/application/rate_limit_status.json + * + * @return the rate limit statuses + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * application/rate_limit_status + * @since Twitter4J 3.0.0 + */ + Map getRateLimitStatus() throws TwitterException; + + /** + * Returns the current rate limits for methods belonging to the specified + * resource families.
+ * Each 1.1 API resource belongs to a "resource family" which is indicated + * in its method documentation. You can typically determine a method's + * resource family from the first component of the path after the resource + * version.
+ * This method responds with a map of methods belonging to the families + * specified by the resources parameter, the current remaining uses for each + * of those resources within the current rate limiting window, and its + * expiration time in epoch time. It also includes a rate_limit_context + * field that indicates the current access token context.
+ * You may also issue requests to this method without any parameters to + * receive a map of all rate limited GET methods. If your application only + * uses a few of methods, please explicitly provide a resources parameter + * with the specified resource families you work with.
+ * Read more about REST API Rate Limiting in v1.1 and review the limits.
+ * As of Nov 4th 2012, supported resource names are as follows: + * "trends& + * quot;,"application","users","saved_searches + * " + * ,"geo","direct_messages","blocks"," + * ;favorites + * ","statuses","followers","help" + * ;,"friends + * ","search","friendships","account + * ","lists"
+ * This method calls + * http://api.twitter.com/1.1/application/rate_limit_status.json + * + * @return the rate limit statuses + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * application/rate_limit_status + * @since Twitter4J 3.0.0 + */ + Map getRateLimitStatus(String... resources) throws TwitterException; + + /** + * Returns Twitter's' Terms of Service.
+ * This method calls http://api.twitter.com/1.1/legal/tos.json + * + * @return Terms of Service + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * legal/tos | Twitter Developers + * @since Twitter4J 2.1.7 + */ + String getTermsOfService() throws TwitterException; + + public static interface Language { + String getCode(); + + String getName(); + + String getStatus(); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/ListsResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/ListsResources.java new file mode 100644 index 00000000..9b91d310 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/ListsResources.java @@ -0,0 +1,480 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.CursorPaging; +import twitter4j.PageableResponseList; +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; +import twitter4j.User; +import twitter4j.UserList; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface ListsResources { + /** + * Adds a member to a list. The authenticated user must own the list to be + * able to add members to it. Lists are limited to having 500 members.
+ * This method calls http://api.twitter.com/1.1/lists/members/create.json + * + * @param listId The id of the list. + * @param userId The id of the user to add as a member of the list. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * lists/members/create | Twitter Developers + * @since Twitter4J 2.1.0 + */ + UserList addUserListMember(long listId, long userId) throws TwitterException; + + UserList addUserListMember(long listId, String userScreenName) throws TwitterException; + + /** + * Adds multiple members to a list, by specifying a comma-separated list of + * member ids or screen names. The authenticated user must own the list to + * be able to add members to it. Lists are limited to having 500 members, + * and you are limited to adding up to 100 members to a list at a time with + * this method.
+ * This method calls + * http://api.twitter.com/1.1/lists/members/create_all.json + * + * @param listId The id of the list. + * @param userIds The array of ids of the user to add as member of the list. + * up to 100 are allowed in a single request. + * @see POST + * lists/members/create_all | Twitter Developers + * @since Twitter4J 2.1.7 + */ + UserList addUserListMembers(long listId, long[] userIds) throws TwitterException; + + /** + * Adds multiple members to a list, by specifying a comma-separated list of + * member ids or screen names. The authenticated user must own the list to + * be able to add members to it. Lists are limited to having 500 members, + * and you are limited to adding up to 100 members to a list at a time with + * this method.
+ * This method calls + * http://api.twitter.com/1.1/lists/members/create_all.json + * + * @param listId The id of the list. + * @param screenNames The array of screen names of the user to add as member + * of the list. up to 100 are allowed in a single request. + * @see POST + * lists/members/create_all | Twitter Developers + * @since Twitter4J 2.1.7 + */ + UserList addUserListMembers(long listId, String[] screenNames) throws TwitterException; + + /** + * Creates a new list for the authenticated user. Accounts are limited to 20 + * lists.
+ * This method calls http://api.twitter.com/1.1/lists/create.json + * + * @param listName The name of the list you are creating. Required. + * @param isPublicList set true if you wish to make a public list + * @param description The description of the list you are creating. + * Optional. + * @return the list that was created + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable, or the authenticated user already has 20 + * lists(TwitterException.getStatusCode() == 403). + * @see POST + * lists/create | Twitter Developers + * @since Twitter4J 2.1.0 + */ + UserList createUserList(String listName, boolean isPublicList, String description) throws TwitterException; + + /** + * Make the authenticated user follow the specified list.
+ * This method calls http://api.twitter.com/1.1/list/subscribers/create.json + * + * @param listId The id of the list. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * lists/subscribers/create | Twitter Developers + * @since Twitter4J 2.2.3 + */ + UserList createUserListSubscription(long listId) throws TwitterException; + + /** + * Removes the specified member from the list. The authenticated user must + * be the list's owner to remove members from the list.
+ * This method calls http://api.twitter.com/1.1/lists/members/destroy.json + * + * @param listId The id of the list. + * @param userId The screen name of the member you wish to remove from the + * list. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * lists/members/destroy | Twitter Developers + * @since Twitter4J 2.1.0 + */ + UserList deleteUserListMember(long listId, long userId) throws TwitterException; + + UserList deleteUserListMember(long listId, String screenName) throws TwitterException; + + UserList deleteUserListMembers(long listId, long[] userIds) throws TwitterException; + + UserList deleteUserListMembers(long listId, String[] screenNames) throws TwitterException; + + /** + * Deletes the specified list. Must be owned by the authenticated user.
+ * This method calls http://api.twitter.com/1.1/lists/destroy.json + * + * @param listId The id of the list to delete + * @return the deleted list + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * lists/destroy | Twitter Developers + * @since Twitter4J 2.1.0 + */ + UserList destroyUserList(long listId) throws TwitterException; + + /** + * Unsubscribes the authenticated user form the specified list.
+ * This method calls http://api.twitter.com/1.1/subscribers/destroy.json + * + * @param listId The id of the list. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * lists/subscribers/destroy | Twitter Developers + * @since Twitter4J 2.2.3 + */ + UserList destroyUserListSubscription(long listId) throws TwitterException; + + /** + * Returns the members of the specified list.
+ * This method calls http://api.twitter.com/1.1/lists/members.json + * + * @param listId The id of the list + * @param paging Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @return the members of the specified list. + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * lists/members | Twitter Developers + * @since Twitter4J 2.2.3 + */ + PageableResponseList getUserListMembers(long listId, CursorPaging paging) throws TwitterException; + + PageableResponseList getUserListMembers(String slug, long ownerId, CursorPaging paging) + throws TwitterException; + + PageableResponseList getUserListMembers(String slug, String ownerScreenName, CursorPaging paging) + throws TwitterException; + + /** + * List the lists the authenticating user has been added to.
+ * This method calls http://api.twitter.com/1.1/lists/memberships.json + * + * @param cursor Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @throws IllegalStateException when authorization is not enabled + * @see GET + * lists/memberships | Twitter Developers + * @since Twitter4J 2.2.4 + */ + PageableResponseList getUserListMemberships(long cursor) throws TwitterException; + + /** + * List the lists the specified user has been added to.
+ * This method calls http://api.twitter.com/1.1/lists/memberships.json + * + * @param listMemberId The id of the list member + * @param cursor Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * lists/memberships | Twitter Developers + * @since Twitter4J 2.2.4 + */ + PageableResponseList getUserListMemberships(long listMemberId, long cursor) throws TwitterException; + + /** + * List the lists the specified user has been added to.
+ * This method calls http://api.twitter.com/1.1/lists/memberships.json + * + * @param listMemberId The id of the list member + * @param cursor Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @param filterToOwnedLists Whether to return just lists the authenticating + * user owns, and the user represented by listMemberId is a + * member of. + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @throws IllegalStateException when filerToOwnedLists is true but + * authorization is not enabled + * @see GET + * lists/memberships | Twitter Developers + * @since Twitter4J 2.2.4 + */ + PageableResponseList getUserListMemberships(long listMemberId, long cursor, boolean filterToOwnedLists) + throws TwitterException; + + /** + * List the lists the specified user has been added to.
+ * This method calls http://api.twitter.com/1.1/lists/memberships.json + * + * @param listMemberScreenName The screen name of the list member + * @param cursor Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * lists/memberships | Twitter Developers + * @since Twitter4J 2.1.0 + */ + PageableResponseList getUserListMemberships(String listMemberScreenName, long cursor) + throws TwitterException; + + /** + * List the lists the specified user has been added to.
+ * This method calls http://api.twitter.com/1.1/lists/memberships.json + * + * @param listMemberScreenName The screen name of the list member + * @param cursor Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @param filterToOwnedLists Whether to return just lists the authenticating + * user owns, and the user represented by listMemberScreenName is + * a member of. + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @throws IllegalStateException when filerToOwnedLists is true but + * authorization is not enabled + * @see GET + * lists/memberships | Twitter Developers + * @since Twitter4J 2.2.4 + */ + PageableResponseList getUserListMemberships(String listMemberScreenName, long cursor, + boolean filterToOwnedLists) throws TwitterException; + + PageableResponseList getUserListOwnerships(long cursor) throws TwitterException; + + PageableResponseList getUserListOwnerships(long listMemberId, long cursor) throws TwitterException; + + PageableResponseList getUserListOwnerships(String listMemberScreenName, long cursor) + throws TwitterException; + + /** + * List the lists of the specified user. Private lists will be included if + * the authenticated users is the same as the user whose lists are being + * returned.
+ * This method calls http://api.twitter.com/1.1/lists.json + * + * @param userId The id of the list owner + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @see GET lists | + * Twitter Developers + * @since Twitter4J 2.2.3 + */ + ResponseList getUserLists(long userId, boolean reverse) throws TwitterException; + + /** + * List the lists of the specified user. Private lists will be included if + * the authenticated users is the same as the user whose lists are being + * returned.
+ * This method calls http://api.twitter.com/1.1/lists.json + * + * @param screenName The screen name of the user + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @see GET lists | + * Twitter Developers + * @since Twitter4J 2.1.0 + */ + ResponseList getUserLists(String screenName, boolean reverse) throws TwitterException; + + /** + * Show tweet timeline for members of the specified list.
+ * http://api.twitter.com/1.1/user/lists/list_id/statuses.json + * + * @param listId The id of the list + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return list of statuses for members of the specified list + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * lists/statuses | Twitter Developers + * @since Twitter4J 2.2.3 + */ + ResponseList getUserListStatuses(long listId, Paging paging) throws TwitterException; + + ResponseList getUserListStatuses(String slug, long ownerId, Paging paging) throws TwitterException; + + ResponseList getUserListStatuses(String slug, String ownerScreenName, Paging paging) + throws TwitterException; + + /** + * Returns the subscribers of the specified list.
+ * This method calls http://api.twitter.com/1.1/lists/subscribers.json + * + * @param listId The id of the list + * @param paging Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @return the members of the specified list. + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * lists/subscribers | Twitter Developers + * @since Twitter4J 2.2.3 + */ + PageableResponseList getUserListSubscribers(long listId, CursorPaging paging) throws TwitterException; + + PageableResponseList getUserListSubscribers(String slug, long ownerId, CursorPaging paging) + throws TwitterException; + + PageableResponseList getUserListSubscribers(String slug, String ownerScreenName, CursorPaging paging) + throws TwitterException; + + /** + * List the lists the specified user follows.
+ * This method calls http://api.twitter.com/1.1/lists/subscriptions.json + * + * @param listOwnerScreenName The screen name of the list owner + * @param cursor Breaks the results into pages. A single page contains 20 + * lists. Provide a value of -1 to begin paging. Provide values + * as returned to in the response body's next_cursor and + * previous_cursor attributes to page back and forth in the list. + * @return the list of lists + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * lists/subscriptions | Twitter Developers + * @since Twitter4J 2.1.0 + */ + PageableResponseList getUserListSubscriptions(String listOwnerScreenName, long cursor) + throws TwitterException; + + /** + * Show the specified list. Private lists will only be shown if the + * authenticated user owns the specified list.
+ * This method calls http://api.twitter.com/1.1/lists/show.json + * + * @param listId The id of the list to show + * @return the specified list + * @throws TwitterException when Twitter service or network is unavailable + * @see https://dev.twitter.com/docs/api/1.1/get/lists/show | Twitter Developers + * @since Twitter4J 2.2.3 + */ + UserList showUserList(long listId) throws TwitterException; + + UserList showUserList(String slug, long ownerId) throws TwitterException; + + UserList showUserList(String slug, String ownerScreenName) throws TwitterException; + + /** + * Check if a user is a member of the specified list.
+ *
+ * This method calls http://api.twitter.com/1.1/lists/members/show.json + * + * @param listId The id of the list. + * @param userId The id of the user who you want to know is a member or not + * of the specified list. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable , + * or the user is not a member of the specified + * list(TwitterException.getStatusCode() returns 404 in that + * case.) + * @see GET + * lists/members/show | Twitter Developers + * @since Twitter4J 2.2.3 + */ + User showUserListMembership(long listId, long userId) throws TwitterException; + + /** + * Check if the specified user is a subscriber of the specified list.
+ * This method calls http://api.twitter.com/1.1/lists/subscribers/show.json + * + * @param listId The id of the list. + * @param userId The id of the user who you want to know is a member or not + * of the specified list. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable , + * or the user is not a member of the specified + * list(TwitterException.getStatusCode() returns 404 in that + * case.) + * @see GET + * lists/subscribers/show | Twitter Developers + * @since Twitter4J 2.2.3 + */ + User showUserListSubscription(long listId, long userId) throws TwitterException; + + /** + * Updates the specified list.
+ * This method calls http://api.twitter.com/1.1/lists/update.json + * + * @param listId The id of the list to update. + * @param newListName What you'd like to change the list's name to. + * @param isPublicList Whether your list is public or private. Optional. + * Values can be public or private. Lists are public by default + * if no mode is specified. + * @param newDescription What you'd like to change the list description to. + * @return the updated list + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * lists/update | Twitter Developers + * @since Twitter4J 2.1.0 + */ + UserList updateUserList(long listId, String newListName, boolean isPublicList, String newDescription) + throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/MediaResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/MediaResources.java new file mode 100644 index 00000000..ef021f16 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/MediaResources.java @@ -0,0 +1,35 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import java.io.File; +import java.io.InputStream; + +import twitter4j.MediaUploadResponse; +import twitter4j.TwitterException; + +public interface MediaResources { + + public MediaUploadResponse uploadMedia(File file) throws TwitterException; + + public MediaUploadResponse uploadMedia(String fileName, InputStream fileBody, String fileType) + throws TwitterException; + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PlacesGeoResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PlacesGeoResources.java new file mode 100644 index 00000000..9b2d4096 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PlacesGeoResources.java @@ -0,0 +1,151 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.GeoLocation; +import twitter4j.GeoQuery; +import twitter4j.Place; +import twitter4j.ResponseList; +import twitter4j.SimilarPlaces; +import twitter4j.TwitterException; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public interface PlacesGeoResources { + /** + * Creates a new place at the given latitude and longitude.
+ * This method calls http://api.twitter.com/1.1/geo/place.json + * + * @param name The name a place is known as. + * @param containedWithin The place_id within which the new place can be + * found. Try and be as close as possible with the containing + * place. For example, for a room in a building, set the + * contained_within as the building place_id. + * @param token The token found in the response from geo/similar_places. + * @param location The latitude and longitude the place is located at. + * @param streetAddress optional: This parameter searches for places which + * have this given street address. There are other well-known, + * and application specific attributes available. Custom + * attributes are also permitted. Learn more about Place + * Attributes. + * @return the created place + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * geo/place | Twitter Developers + * @since Twitter4J 2.1.7 + */ + Place createPlace(String name, String containedWithin, String token, GeoLocation location, String streetAddress) + throws TwitterException; + + /** + * Find out more details of a place that was returned from the + * {@link PlacesGeoResources#reverseGeoCode(twitter4j.GeoQuery)} + * method.
+ * This method calls http://api.twitter.com/1.1/geo/id/:id.json + * + * @param id The ID of the location to query about. + * @return details of the specified place + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * geo/id/:place_id | Twitter Developers + * @since Twitter4J 2.1.1 + */ + Place getGeoDetails(String id) throws TwitterException; + + /** + * Locates places near the given coordinates which are similar in name.
+ * Conceptually you would use this method to get a list of known places to + * choose from first. Then, if the desired place doesn't exist, make a + * request to post/geo/place to create a new one.
+ * The token contained in the response is the token needed to be able to + * create a new place.
+ * This method calls http://api.twitter.com/1.1/geo/similar_places.json + * + * @param location The latitude and longitude to search around. + * @param name The name a place is known as. + * @param containedWithin optional: the place_id which you would like to + * restrict the search results to. Setting this value means only + * places within the given place_id will be found. + * @param streetAddress optional: This parameter searches for places which + * have this given street address. There are other well-known, + * and application specific attributes available. Custom + * attributes are also permitted. Learn more about Place + * Attributes. + * @return places (cities and neighborhoods) that can be attached to a + * statuses/update + * @throws TwitterException when Twitter service or network is unavailable + * @since Twitter4J 2.1.7 + */ + SimilarPlaces getSimilarPlaces(GeoLocation location, String name, String containedWithin, String streetAddress) + throws TwitterException; + + /** + * Search for places (cities and neighborhoods) that can be attached to a + * statuses/update. Given a latitude and a longitude, return a list of all + * the valid places that can be used as a place_id when updating a status. + * Conceptually, a query can be made from the user's location, retrieve a + * list of places, have the user validate the location he or she is at, and + * then send the ID of this location up with a call to statuses/update.
+ * There are multiple granularities of places that can be returned -- + * "neighborhoods", "cities", etc. At this time, only United States data is + * available through this method.
+ * This API call is meant to be an informative call and will deliver + * generalized results about geography.
+ * This method calls http://api.twitter.com/1.1/geo/reverse_geocode.json + * + * @param query search query + * @return places (cities and neighborhoods) that can be attached to a + * statuses/update + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * geo/reverse_geocode | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList reverseGeoCode(GeoQuery query) throws TwitterException; + + /** + * Search for places that can be attached to a statuses/update. Given a + * latitude and a longitude pair, an IP address, or a name, this request + * will return a list of all the valid places that can be used as the + * place_id when updating a status.
+ * Conceptually, a query can be made from the user's location, retrieve a + * list of places, have the user validate the location he or she is at, and + * then send the ID of this location with a call to statuses/update.
+ * This is the recommended method to use find places that can be attached to + * statuses/update. Unlike geo/reverse_geocode which provides raw data + * access, this endpoint can potentially re-order places with regards to the + * user who is authenticated. This approach is also preferred for + * interactive place matching with the user.
+ * This method calls http://api.twitter.com/1.1/geo/search.json + * + * @param query search query + * @return places (cities and neighborhoods) that can be attached to a + * statuses/update + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * geo/search | Twitter Developers + * @since Twitter4J 2.1.7 + */ + ResponseList searchPlaces(GeoQuery query) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateActivityResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateActivityResources.java new file mode 100644 index 00000000..09e96c6f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateActivityResources.java @@ -0,0 +1,16 @@ +package twitter4j.api; + +import twitter4j.Activity; +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.TwitterException; + +public interface PrivateActivityResources extends PrivateResources { + public ResponseList getActivitiesAboutMe() throws TwitterException; + + public ResponseList getActivitiesAboutMe(Paging paging) throws TwitterException; + + public ResponseList getActivitiesByFriends() throws TwitterException; + + public ResponseList getActivitiesByFriends(Paging paging) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateDirectMessagesResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateDirectMessagesResources.java new file mode 100644 index 00000000..f092e459 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateDirectMessagesResources.java @@ -0,0 +1,31 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.TwitterException; + +/** + * Created by mariotaku on 15/1/6. + */ +public interface PrivateDirectMessagesResources extends PrivateResources { + + void destroyDirectMessagesConversation(long userId) throws TwitterException; + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateFriendsFollowersResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateFriendsFollowersResources.java new file mode 100644 index 00000000..7d2bed67 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateFriendsFollowersResources.java @@ -0,0 +1,16 @@ +package twitter4j.api; + +import twitter4j.TwitterException; +import twitter4j.User; + +public interface PrivateFriendsFollowersResources extends PrivateResources { + + public User acceptFriendship(long userId) throws TwitterException; + + public User acceptFriendship(String screenName) throws TwitterException; + + public User denyFriendship(long userId) throws TwitterException; + + public User denyFriendship(String screenName) throws TwitterException; + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateResources.java new file mode 100644 index 00000000..6dcedd72 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateResources.java @@ -0,0 +1,5 @@ +package twitter4j.api; + +public interface PrivateResources { + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateTimelinesResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateTimelinesResources.java new file mode 100644 index 00000000..89ceca74 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateTimelinesResources.java @@ -0,0 +1,21 @@ +package twitter4j.api; + +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; + +public interface PrivateTimelinesResources extends PrivateResources { + + ResponseList getMediaTimeline() throws TwitterException; + + ResponseList getMediaTimeline(long userId) throws TwitterException; + + ResponseList getMediaTimeline(long userId, Paging paging) throws TwitterException; + + ResponseList getMediaTimeline(Paging paging) throws TwitterException; + + ResponseList getMediaTimeline(String screenName) throws TwitterException; + + ResponseList getMediaTimeline(String screenName, Paging paging) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateTweetResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateTweetResources.java new file mode 100644 index 00000000..1092cc4c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/PrivateTweetResources.java @@ -0,0 +1,21 @@ +package twitter4j.api; + +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.StatusActivitySummary; +import twitter4j.TranslationResult; +import twitter4j.TwitterException; + +public interface PrivateTweetResources extends PrivateResources { + + StatusActivitySummary getStatusActivitySummary(long statusId) throws TwitterException; + + StatusActivitySummary getStatusActivitySummary(long statusId, boolean includeUserEntities) throws TwitterException; + + ResponseList showConversation(long statusId) throws TwitterException; + + ResponseList showConversation(long statusId, Paging paging) throws TwitterException; + + TranslationResult showTranslation(long statusId, String dest) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/SavedSearchesResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/SavedSearchesResources.java new file mode 100644 index 00000000..85cac8e4 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/SavedSearchesResources.java @@ -0,0 +1,86 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.api; + +import twitter4j.ResponseList; +import twitter4j.SavedSearch; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface SavedSearchesResources { + /** + * Creates a saved search for the authenticated user.
+ * This method calls + * http://api.twitter.com/1.1/saved_searches/saved_searches/create.json + * + * @param query the query string + * @return the data for a created saved search + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * saved_searches/create | Twitter Developers + * @since Twitter4J 2.0.8 + */ + SavedSearch createSavedSearch(String query) throws TwitterException; + + /** + * Destroys a saved search for the authenticated user. The search specified + * by id must be owned by the authenticating user.
+ * This method calls + * http://api.twitter.com/1.1/saved_searches/destroy/id.json + * + * @param id The id of the saved search to be deleted. + * @return the data for a destroyed saved search + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * saved_searches/destroy/:id | Twitter Developers + * @since Twitter4J 2.0.8 + */ + SavedSearch destroySavedSearch(int id) throws TwitterException; + + /** + * Returns the authenticated user's saved search queries.
+ * This method calls http://api.twitter.com/1.1/saved_searches.json + * + * @return Returns an array of numeric user ids the authenticating user is + * blocking. + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * saved_searches | Twitter Developers + * @since Twitter4J 2.0.8 + */ + ResponseList getSavedSearches() throws TwitterException; + + /** + * Retrieve the data for a saved search owned by the authenticating user + * specified by the given id.
+ * This method calls http://api.twitter.com/1.1/saved_searches/show/:id.json + * + * @param id The id of the saved search to be retrieved. + * @return the data for a saved search + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * saved_searches/show/:id | Twitter Developers + * @since Twitter4J 2.0.8 + */ + SavedSearch showSavedSearch(int id) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/SearchResource.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/SearchResource.java new file mode 100644 index 00000000..6701e79d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/SearchResource.java @@ -0,0 +1,41 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.api; + +import twitter4j.Query; +import twitter4j.QueryResult; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface SearchResource { + /** + * Returns tweets that match a specified query.
+ * This method calls http://search.twitter.com/search.json + * + * @param query - the search condition + * @return the result + * @throws TwitterException when Twitter service or network is unavailable + * @see GET search + * | Twitter Developers + * @see Twitter API / Search + * Operators + * @since Twitter4J 1.1.7 + */ + QueryResult search(Query query) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/SpamReportingResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/SpamReportingResources.java new file mode 100644 index 00000000..000a6e7b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/SpamReportingResources.java @@ -0,0 +1,55 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.api; + +import twitter4j.TwitterException; +import twitter4j.User; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface SpamReportingResources { + + /** + * The user specified in the id is blocked by the authenticated user and + * reported as a spammer.
+ * This method calls http://api.twitter.com/1.1/report_spam.json + * + * @param userId The ID of the user you want to report as a spammer. + * @return The User reported as a spammer. + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * report_spam | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User reportSpam(long userId) throws TwitterException; + + /** + * The user specified in the id is blocked by the authenticated user and + * reported as a spammer.
+ * This method calls http://api.twitter.com/1.1/report_spam.json + * + * @param screenName The screen name of the user you want to report as a + * spammer. + * @return The User reported as a spammer. + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * report_spam | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User reportSpam(String screenName) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/TimelinesResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/TimelinesResources.java new file mode 100644 index 00000000..cb0f81bf --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/TimelinesResources.java @@ -0,0 +1,284 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.Paging; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface TimelinesResources { + /** + * Returns the 20 most recent statuses, including retweets, posted by the + * authenticating user and that user's friends. This is the equivalent of + * /timeline/home on the Web.
+ * Usage note: This home_timeline call is identical to + * statuses/friends_timeline, except that home_timeline also contains + * retweets, while statuses/friends_timeline does not for backwards + * compatibility reasons. In a future version of the API, + * statuses/friends_timeline will be deprected and replaced by + * home_timeline.
+ * This method calls http://api.twitter.com/1.1/statuses/home_timeline + * + * @return list of the home Timeline + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/home_timeline | Twitter Developers + * @since Twitter4J 2.0.10 + */ + ResponseList getHomeTimeline() throws TwitterException; + + /** + * Returns the 20 most recent statuses, including retweets, posted by the + * authenticating user and that user's friends. This is the equivalent of + * /timeline/home on the Web.
+ * Usage note: This home_timeline call is identical to + * statuses/friends_timeline, except that home_timeline also contains + * retweets, while statuses/friends_timeline does not for backwards + * compatibility reasons. In a future version of the API, + * statuses/friends_timeline will be deprected and replaced by + * home_timeline.
+ * This method calls http://api.twitter.com/1.1/statuses/home_timeline + * + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return list of the home Timeline + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/home_timeline | Twitter Developers + * @since Twitter4J 2.0.10 + */ + ResponseList getHomeTimeline(Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent mentions (status containing @username) for the + * authenticating user.
+ * This method calls http://api.twitter.com/1.1/statuses/mentions_timeline + * + * @return the 20 most recent replies + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/mentions | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getMentionsTimeline() throws TwitterException; + + /** + * Returns the 20 most recent mentions (status containing @username) for the + * authenticating user.
+ * This method calls http://api.twitter.com/1.1/statuses/mentions_timeline + * + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return the 20 most recent replies + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/mentions | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getMentionsTimeline(Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent tweets of the authenticated user that have + * been retweeted by others.
+ * This method calls http://api.twitter.com/1.1/statuses/retweets_of_me.json + * + * @return the 20 most recent tweets of the authenticated user that have + * been retweeted by others. + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/retweets_of_me | Twitter Developers + * @since Twitter4J 2.0.10 + */ + ResponseList getRetweetsOfMe() throws TwitterException; + + /** + * Returns the 20 most recent tweets of the authenticated user that have + * been retweeted by others.
+ * This method calls http://api.twitter.com/1.1/statuses/retweets_of_me.json + * + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return the 20 most recent tweets of the authenticated user that have + * been retweeted by others. + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/retweets_of_me | Twitter Developers + * @since Twitter4J 2.0.10 + */ + ResponseList getRetweetsOfMe(Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent statuses posted from the authenticating user. + * It's also possible to request another user's timeline via the id + * parameter.
+ * This is the equivalent of the Web / page for your own user, or the + * profile page for a third party.
+ * For backwards compatibility reasons, retweets are stripped out of the + * user_timeline when calling in XML or JSON (they appear with 'RT' in RSS + * and Atom). If you'd like them included, you can merge them in from + * statuses retweeted_by_me.
+ *
+ * This method calls http://api.twitter.com/1.1/statuses/user_timeline + * + * @return the 20 most recent statuses posted in the last 24 hours from the + * user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/user_timeline | Twitter Developers + */ + ResponseList getUserTimeline() throws TwitterException; + + /** + * Returns the 20 most recent statuses posted from the authenticating user. + * It's also possible to request another user's timeline via the id + * parameter.
+ * This is the equivalent of the Web / page for your own user, or the + * profile page for a third party.
+ * For backwards compatibility reasons, retweets are stripped out of the + * user_timeline when calling in XML or JSON (they appear with 'RT' in RSS + * and Atom). If you'd like them included, you can merge them in from + * statuses retweeted_by_me.
+ *
+ * This method calls http://api.twitter.com/1.1/statuses/user_timeline + * + * @param userId specifies the ID of the user for whom to return the + * user_timeline + * @return the 20 most recent statuses posted in the last 24 hours from the + * user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/user_timeline | Twitter Developers + * @since Twitter4J 2.1.0 + */ + ResponseList getUserTimeline(long userId) throws TwitterException; + + /** + * Returns the 20 most recent statuses posted from the authenticating user. + * It's also possible to request another user's timeline via the id + * parameter.
+ * This is the equivalent of the Web / page for your own user, or the + * profile page for a third party.
+ * For backwards compatibility reasons, retweets are stripped out of the + * user_timeline when calling in XML or JSON (they appear with 'RT' in RSS + * and Atom). If you'd like them included, you can merge them in from + * statuses retweeted_by_me.
+ *
+ * This method calls http://api.twitter.com/1.1/statuses/user_timeline.json + * + * @param userId specifies the ID of the user for whom to return the + * user_timeline + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return list of the user Timeline + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/user_timeline | Twitter Developers + * @since Twitter4J 2.1.0 + */ + ResponseList getUserTimeline(long userId, Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent statuses posted from the authenticating user. + * It's also possible to request another user's timeline via the id + * parameter.
+ * This is the equivalent of the Web / page for your own user, or the + * profile page for a third party.
+ * For backwards compatibility reasons, retweets are stripped out of the + * user_timeline when calling in XML or JSON (they appear with 'RT' in RSS + * and Atom). If you'd like them included, you can merge them in from + * statuses retweeted_by_me.
+ *
+ * This method calls http://api.twitter.com/1.1/statuses/user_timeline + * + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return the 20 most recent statuses posted in the last 24 hours from the + * user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/user_timeline | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getUserTimeline(Paging paging) throws TwitterException; + + /** + * Returns the 20 most recent statuses posted from the authenticating user. + * It's also possible to request another user's timeline via the id + * parameter.
+ * This is the equivalent of the Web / page for your own user, or the + * profile page for a third party.
+ * For backwards compatibility reasons, retweets are stripped out of the + * user_timeline when calling in XML or JSON (they appear with 'RT' in RSS + * and Atom). If you'd like them included, you can merge them in from + * statuses retweeted_by_me.
+ *
+ * This method calls http://api.twitter.com/1.1/statuses/user_timeline + * + * @param screenName specifies the screen name of the user for whom to + * return the user_timeline + * @return the 20 most recent statuses posted in the last 24 hours from the + * user + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/user_timeline | Twitter Developers + */ + ResponseList getUserTimeline(String screenName) throws TwitterException; + + /** + * Returns the 20 most recent statuses posted from the authenticating user. + * It's also possible to request another user's timeline via the id + * parameter.
+ * This is the equivalent of the Web / page for your own user, or the + * profile page for a third party.
+ * For backwards compatibility reasons, retweets are stripped out of the + * user_timeline when calling in XML or JSON (they appear with 'RT' in RSS + * and Atom). If you'd like them included, you can merge them in from + * statuses retweeted_by_me.
+ *
+ * This method calls http://api.twitter.com/1.1/statuses/user_timeline.json + * + * @param screenName specifies the screen name of the user for whom to + * return the user_timeline + * @param paging controls pagination. Supports since_id, max_id, count and + * page parameters. + * @return list of the user Timeline + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/user_timeline | Twitter Developers + * @since Twitter4J 2.0.1 + */ + ResponseList getUserTimeline(String screenName, Paging paging) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/TrendsResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/TrendsResources.java new file mode 100644 index 00000000..07081c95 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/TrendsResources.java @@ -0,0 +1,139 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.api; + +import twitter4j.GeoLocation; +import twitter4j.Location; +import twitter4j.ResponseList; +import twitter4j.Trends; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface TrendsResources { + /** + * Returns the locations that Twitter has trending topic information for. + * The response is an array of "locations" that encode the + * location's WOEID (a Yahoo! Where On Earth + * ID) and some other human-readable information such as a canonical + * name and country the location belongs in.
+ * This method calls http://api.twitter.com/1.1/trends/available.json + * + * @return the locations + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * trends/available | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList getAvailableTrends() throws TwitterException; + + /** + * Returns the sorted locations that Twitter has trending topic information + * for. The response is an array of "locations" that encode the + * location's WOEID (a Yahoo! Where On Earth + * ID) and some other human-readable information such as a canonical + * name and country the location belongs in.
+ * This method calls http://api.twitter.com/1.1/trends/available.json + * + * @param location the available trend locations will be sorted by distance + * to the lat and long passed in. The sort is nearest to + * furthest. + * @return the locations + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * trends/available | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList getAvailableTrends(GeoLocation location) throws TwitterException; + + /** + * Returns the locations that Twitter has trending topic information for, + * closest to a specified location.
+ * The response is an array of "locations" that encode the location's WOEID + * and some other human-readable information such as a canonical name and + * country the location belongs in.
+ * A WOEID is a Yahoo! + * Where On Earth ID.
+ * This method calls http://api.twitter.com/1.1/trends/closest.json + * + * @param location the available trend locations will be sorted by distance + * to the lat and long passed in. The sort is nearest to + * furthest. + * @return the locations + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * trends/closest | Twitter Developers + * @since Twitter4J 3.0.2 + */ + ResponseList getClosestTrends(GeoLocation location) throws TwitterException; + + /** + * Returns the top 10 trending topics for a specific location Twitter has + * trending topic information for. The response is an array of "trend" + * objects that encode the name of the trending topic, the query parameter + * that can be used to search for the topic on Search, and the direct URL + * that can be issued against Search. This information is cached for five + * minutes, and therefore users are discouraged from querying these + * endpoints faster than once every five minutes. Global trends information + * is also available from this API by using a WOEID of 1.
+ * This method calls http://api.twitter.com/1.1/trends/:woeid.json + * + * @param woeid The WOEID of the location to be querying for + * @return trends + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * trends/:woeid | Twitter Developers + * @since Twitter4J 2.1.1 + */ + Trends getLocationTrends(int woeid) throws TwitterException; + + /** + * Returns the top 10 trending topics for a specific WOEID, if trending + * information is available for it.
+ * The response is an array of "trend" objects that encode the name of the + * trending topic, the query parameter that can be used to search for the + * topic on Twitter Search, and the + * Twitter Search URL.
+ * This information is cached for 5 minutes. Requesting more frequently than + * that will not return any more data, and will count against your rate + * limit usage.
+ *
+ * This method calls http://api.twitter.com/1.1/trends/place.json + * + * @param woeid The + * Yahoo! Where On Earth ID of the location to return + * trending information for. Global information is available by + * using 1 as the WOEID. + * @return trends + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * trends/place | Twitter Developers + * @since Twitter4J 3.0.2 + */ + Trends getPlaceTrends(int woeid) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/TweetResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/TweetResources.java new file mode 100644 index 00000000..efbdf3f4 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/TweetResources.java @@ -0,0 +1,177 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import twitter4j.CursorPaging; +import twitter4j.IDs; +import twitter4j.OEmbed; +import twitter4j.OEmbedRequest; +import twitter4j.ReportAs; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.StatusUpdate; +import twitter4j.TwitterException; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface TweetResources { + /** + * Destroys the status specified by the required ID parameter.
+ * Usage note: The authenticating user must be the author of the specified + * status.
+ * This method calls http://api.twitter.com/1.1/statuses/destroy + * + * @param statusId The ID of the status to destroy. + * @return the deleted status + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * statuses/destroy/:id | Twitter Developers + * @since 1.0.5 + */ + Status destroyStatus(long statusId) throws TwitterException; + + /** + * Returns information allowing the creation of an embedded representation + * of a Tweet on third party sites. See the oEmbed specification for information about + * the response format. While this endpoint allows a bit of customization + * for the final appearance of the embedded Tweet, be aware that the + * appearance of the rendered Tweet may change over time to be consistent + * with Twitter's Display + * Requirements. Do not rely on any class or id parameters to stay + * constant in the returned markup.
+ * This method calls http://api.twitter.com/1.1/statuses/oembed.json + * + * @param req request + * @return information allowing the creation of an embedded representation + * of a Tweet on third party sites + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see GET + * statuses/oembed | Twitter Developers + * @since Twitter4J 3.0.2 + */ + OEmbed getOEmbed(OEmbedRequest req) throws TwitterException; + + IDs getRetweetersIDs(long statusId) throws TwitterException; + + IDs getRetweetersIDs(long statusId, CursorPaging paging) throws TwitterException; + + /** + * Returns up to 100 of the first retweets of a given tweet.
+ * This method calls http://api.twitter.com/1.1/statuses/retweets + * + * @param statusId The numerical ID of the tweet you want the retweets of. + * @return the retweets of a given tweet + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see Tweets + * Resources › statuses/retweets/:id + * @since Twitter4J 2.0.10 + */ + ResponseList getRetweets(long statusId) throws TwitterException; + + /** + * Returns up to 100 of the first retweets of a given tweet.
+ * This method calls http://api.twitter.com/1.1/statuses/retweets + * + * @param statusId The numerical ID of the desired status. + * @param count Specifies the number of records to retrieve. Must be less + * than or equal to 100. + * @return the retweets of a given tweet + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see Tweets + * Resources › statuses/retweets/:id + * @since Twitter4J 2.0.10 + */ + ResponseList getRetweets(long statusId, int count) throws TwitterException; + + int reportSpam(long statusId, ReportAs reportAs, boolean blockUser) throws TwitterException; + + /** + * Retweets a tweet. Returns the original tweet with retweet details + * embedded.
+ * This method calls http://api.twitter.com/1.1/statuses/retweet + * + * @param statusId The ID of the status to retweet. + * @return the retweeted status + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * statuses/retweet/:id | Twitter Developers + * @since Twitter4J 2.0.10 + */ + Status retweetStatus(long statusId) throws TwitterException; + + /** + * Returns a single status, specified by the id parameter below. The + * status's author will be returned inline.
+ * This method calls http://api.twitter.com/1.1/statuses/show + * + * @param id the numerical ID of the status you're trying to retrieve + * @return a single status + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable + * @see GET + * statuses/show/:id | Twitter Developers + * @since Twitter4J 2.0.1 + */ + Status showStatus(long id) throws TwitterException; + + /** + * Updates the authenticating user's status. A status update with text + * identical to the authenticating user's text identical to the + * authenticating user's current status will be ignored to prevent + * duplicates.
+ * This method calls http://api.twitter.com/1.1/statuses/update or
+ * This method calls https://upload.twitter.com/1/statuses/update_with_media + * + * @param latestStatus the latest status to be updated. + * @return the latest status + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * statuses/update | Twitter Developers + * @since Twitter4J 2.1.1 + */ + Status updateStatus(StatusUpdate latestStatus) throws TwitterException; + + /** + * Updates the authenticating user's status. A status update with text + * identical to the authenticating user's text identical to the + * authenticating user's current status will be ignored to prevent + * duplicates.
+ * This method calls http://api.twitter.com/1.1/statuses/update + * + * @param status the text of your status update + * @return the latest status + * @throws twitter4j.TwitterException when Twitter service or network is unavailable + * @see POST + * statuses/update | Twitter Developers + * @since Twitter4J 2.0.1 + */ + Status updateStatus(String status) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/api/UsersResources.java b/firetweet.component.twitter4j/src/main/java/twitter4j/api/UsersResources.java new file mode 100644 index 00000000..ba45501f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/api/UsersResources.java @@ -0,0 +1,580 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.api; + +import java.io.File; +import java.io.InputStream; + +import twitter4j.AccountSettings; +import twitter4j.Category; +import twitter4j.CursorPaging; +import twitter4j.IDs; +import twitter4j.PageableResponseList; +import twitter4j.ResponseList; +import twitter4j.SettingsUpdate; +import twitter4j.TwitterException; +import twitter4j.User; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + */ +public interface UsersResources { + /** + * Blocks the user specified in the ID parameter as the authenticating user. + * Returns the blocked user in the requested format when successful.
+ * This method calls http://api.twitter.com/1.1/blocks/create/[id].json + * + * @param userId the ID of the user to block + * @return the blocked user + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * blocks/create | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User createBlock(long userId) throws TwitterException; + + /** + * Blocks the user specified in the ID parameter as the authenticating user. + * Returns the blocked user in the requested format when successful.
+ * This method calls http://api.twitter.com/1.1/blocks/create/[id].json + * + * @param screenName the screen_name of the user to block + * @return the blocked user + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * blocks/create | Twitter Developers + * @since Twitter4J 2.0.1 + */ + User createBlock(String screenName) throws TwitterException; + + User createMute(long userId) throws TwitterException; + + User createMute(String screenName) throws TwitterException; + + /** + * Un-blocks the user specified in the ID parameter as the authenticating + * user. Returns the un-blocked user in the requested format when + * successful.
+ * This method calls http://api.twitter.com/1.1/blocks/destroy/[id].json + * + * @param userId the ID of the user to block + * @return the unblocked user + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * blocks/destroy | Twitter Developers + * @since Twitter4J 2.0.1 + */ + User destroyBlock(long userId) throws TwitterException; + + /** + * Un-blocks the user specified in the ID parameter as the authenticating + * user. Returns the un-blocked user in the requested format when + * successful.
+ * This method calls http://api.twitter.com/1.1/blocks/destroy/[id].json + * + * @param screenName the screen name of the user to block + * @return the unblocked user + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * blocks/destroy | Twitter Developers + * @since Twitter4J 2.0.1 + */ + User destroyBlock(String screenName) throws TwitterException; + + User destroyMute(long userId) throws TwitterException; + + User destroyMute(String screenName) throws TwitterException; + + /** + * Returns the current trend, geo, language, timezone and sleep time + * information for the authenticating user.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls http://api.twitter.com/1.1/account/settings.json + * + * @return the current trend, geo and sleep time information for the + * authenticating user. + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * account/settings | Twitter Developers + * @since Twitter4J 2.1.9 + */ + AccountSettings getAccountSettings() throws TwitterException; + + /** + * Returns an array of numeric user ids the authenticating user is blocking.
+ * This method calls http://api.twitter.com/1.1/blocks/blocks/ids + * + * @return Returns an array of numeric user ids the authenticating user is + * blocking. + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * blocks/ids | Twitter Developers + * @since Twitter4J 2.0.4 + */ + IDs getBlocksIDs() throws TwitterException; + + IDs getBlocksIDs(CursorPaging paging) throws TwitterException; + + /** + * Returns a list of user objects that the authenticating user is blocking.
+ * This method calls http://api.twitter.com/1.1/blocks/blocking.json + * + * @return a list of user objects that the authenticating user + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * blocks/blocking | Twitter Developers + * @since Twitter4J 2.0.4 + */ + PageableResponseList getBlocksList() throws TwitterException; + + PageableResponseList getBlocksList(CursorPaging paging) throws TwitterException; + + /** + * Access the users in a given category of the Twitter suggested user list + * and return their most recent status if they are not a protected user.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls + * http://api.twitter.com/1.1/users/suggestions/:slug/members.json + * + * @param categorySlug slug + * @return list of suggested users + * @throws TwitterException when Twitter service or network is unavailable + * @see #newtwitter + * and the API - Twitter API Announcements | Google Group + * @since Twitter4J 2.1.9 + */ + ResponseList getMemberSuggestions(String categorySlug) throws TwitterException; + + IDs getMutesUsersIDs() throws TwitterException; + + IDs getMutesUsersIDs(CursorPaging paging) throws TwitterException; + + PageableResponseList getMutesUsersList() throws TwitterException; + + PageableResponseList getMutesUsersList(CursorPaging paging) throws TwitterException; + + /** + * Access to Twitter's suggested user list. This returns the list of + * suggested user categories. The category can be used in the + * users/suggestions/category endpoint to get the users in that category.
+ * This method calls http://api.twitter.com/1.1/users/suggestions/:slug.json + * + * @return list of suggested user categories. + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/suggestions/:slug | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList getSuggestedUserCategories() throws TwitterException; + + /** + * Access the users in a given category of the Twitter suggested user list.
+ * It is recommended that end clients cache this data for no more than one + * hour.
+ * This method calls http://api.twitter.com/1.1/users/suggestions/:slug.json + * + * @param categorySlug slug + * @return list of suggested users + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/suggestions/slug | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList getUserSuggestions(String categorySlug) throws TwitterException; + + /** + * Return up to 100 users worth of extended information, specified by either + * ID, screen name, or combination of the two. The author's most recent + * status (if the authenticating user has permission) will be returned + * inline.
+ * This method calls http://api.twitter.com/1.1/users/lookup.json + * + * @param ids Specifies the screen names of the users to return. + * @return users + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/lookup | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList lookupUsers(long[] ids) throws TwitterException; + + /** + * Return up to 100 users worth of extended information, specified by either + * ID, screen name, or combination of the two. The author's most recent + * status (if the authenticating user has permission) will be returned + * inline.
+ * This method calls http://api.twitter.com/1.1/users/lookup.json + * + * @param screenNames Specifies the screen names of the users to return. + * @return users + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/lookup | Twitter Developers + * @since Twitter4J 2.1.1 + */ + ResponseList lookupUsers(String[] screenNames) throws TwitterException; + + void removeProfileBannerImage() throws TwitterException; + + /** + * Run a search for users similar to the Find People button on Twitter.com; + * the same results returned by people search on Twitter.com will be + * returned by using this API.
+ * Usage note: It is only possible to retrieve the first 1000 matches from + * this API.
+ * This method calls http://api.twitter.com/1.1/users/search.json + * + * @param query The query to run against people search. + * @param page Specifies the page of results to retrieve. Number of statuses + * per page is fixed to 20. + * @return the list of Users matches the provided + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/search | Twitter Developers + */ + ResponseList searchUsers(String query, int page) throws TwitterException; + + /** + * Returns extended information of a given user, specified by ID or screen + * name as per the required id parameter. The author's most recent status + * will be returned inline.
+ * This method calls http://api.twitter.com/1.1/users/show.json + * + * @param userId the ID of the user for whom to request the detail + * @return users + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/show | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User showUser(long userId) throws TwitterException; + + /** + * Returns extended information of a given user, specified by ID or screen + * name as per the required id parameter. The author's most recent status + * will be returned inline.
+ * This method calls http://api.twitter.com/1.1/users/show.json + * + * @param screenName the screen name of the user for whom to request the + * detail + * @return User + * @throws TwitterException when Twitter service or network is unavailable + * @see GET + * users/show | Twitter Developers + */ + User showUser(String screenName) throws TwitterException; + + /** + * Updates the current trend, geo, language, timezone and sleep time + * information for the authenticating user.
+ * This method has not been finalized and the interface is subject to change + * in incompatible ways.
+ * This method calls http://api.twitter.com/1.1/account/settings.json + * + * @param settingsUpdate Settings to be updated + * @return the current trend, geo and sleep time information for the + * authenticating user. + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * account/settings | Twitter Developers + * @since Twitter4J 2.2.4 + */ + AccountSettings updateAccountSettings(SettingsUpdate settingsUpdate) throws TwitterException; + + /** + * Sets values that users are able to set under the "Account" tab of their + * settings page. Only the parameters specified(non-null) will be updated.
+ * This method calls http://api.twitter.com/1.1/account/update_profile.json + * + * @param name Optional. Maximum of 20 characters. + * @param url Optional. Maximum of 100 characters. Will be prepended with + * "http://" if not present. + * @param location Optional. Maximum of 30 characters. The contents are not + * normalized or geocoded in any way. + * @param description Optional. Maximum of 160 characters. + * @return the updated user + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * account/update_profile | Twitter Developers + * @since Twitter4J 2.1.8 + */ + User updateProfile(String name, String url, String location, String description) throws TwitterException; + + /** + * Updates the authenticating user's profile background image.
+ * This method calls + * http://api.twitter.com/1.1/account/update_profile_background_image.json + * + * @param image Must be a valid GIF, JPG, or PNG image of less than 800 + * kilobytes in size. Images with width larger than 2048 pixels + * will be forceably scaled down. + * @param tile If set to true the background image will be displayed tiled. + * The image will not be tiled otherwise. + * @return the updated user + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + * @see POST + * account/update_profile_background_image | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User updateProfileBackgroundImage(File image, boolean tile) throws TwitterException; + + /** + * Updates the authenticating user's profile background image.
+ * This method calls + * http://api.twitter.com/1.1/account/update_profile_background_image.json + * + * @param image Must be a valid GIF, JPG, or PNG image of less than 800 + * kilobytes in size. Images with width larger than 2048 pixels + * will be forceably scaled down. + * @param tile If set to true the background image will be displayed tiled. + * The image will not be tiled otherwise. + * @return the updated user + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + * @see POST + * account/update_profile_background_image | Twitter Developers + * @since Twitter4J 2.1.11 + */ + User updateProfileBackgroundImage(InputStream image, boolean tile) throws TwitterException; + + /** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Code(s)Meaning
200,201,202Profile banner image successfully uploaded
400Either an image was not provided or the image data could be processed + *
422The image could not be resized or it too large
+ * + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + */ + void updateProfileBannerImage(File banner) throws TwitterException; + + /** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Code(s)Meaning
200,201,202Profile banner image successfully uploaded
400Either an image was not provided or the image data could be processed + *
422The image could not be resized or it too large
+ * + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + */ + void updateProfileBannerImage(File banner, int width, int height, int offsetLeft, int offsetTop) + throws TwitterException; + + /** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Code(s)Meaning
200,201,202Profile banner image successfully uploaded
400Either an image was not provided or the image data could be processed + *
422The image could not be resized or it too large
+ * + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + */ + void updateProfileBannerImage(InputStream banner) throws TwitterException; + + /** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Code(s)Meaning
200,201,202Profile banner image successfully uploaded
400Either an image was not provided or the image data could be processed + *
422The image could not be resized or it too large
+ * + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + */ + void updateProfileBannerImage(InputStream banner, int width, int height, int offsetLeft, int offsetTop) + throws TwitterException; + + /** + * Sets one or more hex values that control the color scheme of the + * authenticating user's profile page on twitter.com. Each parameter's value + * must be a valid hexidecimal value, and may be either three or six + * characters (ex: #fff or #ffffff).
+ * This method calls + * http://api.twitter.com/1.1/account/update_profile_colors.json + * + * @param profileBackgroundColor optional, can be null + * @param profileTextColor optional, can be null + * @param profileLinkColor optional, can be null + * @param profileSidebarFillColor optional, can be null + * @param profileSidebarBorderColor optional, can be null + * @return the updated user + * @throws TwitterException when Twitter service or network is unavailable + * @see POST + * account/update_profile_colors | Twitter Developers + * @since Twitter4J 2.0.0 + */ + User updateProfileColors(String profileBackgroundColor, String profileTextColor, String profileLinkColor, + String profileSidebarFillColor, String profileSidebarBorderColor) throws TwitterException; + + /** + * Updates the authenticating user's profile image.
+ * This method calls + * http://api.twitter.com/1.1/account/update_profile_image.json + * + * @param image Must be a valid GIF, JPG, or PNG image of less than 700 + * kilobytes in size. Images with width larger than 500 pixels + * will be scaled down. + * @return the updated user + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + * @see POST + * account/update_profile_image | Twitter Developers + * @since Twitter4J 2.1.0 + */ + User updateProfileImage(File image) throws TwitterException; + + /** + * Updates the authenticating user's profile image.
+ * This method calls + * http://api.twitter.com/1.1/account/update_profile_image.json + * + * @param image Must be a valid GIF, JPG, or PNG image of less than 700 + * kilobytes in size. Images with width larger than 500 pixels + * will be scaled down. + * @return the updated user + * @throws TwitterException when Twitter service or network is unavailable, + * or when the specified file is not found + * (FileNotFoundException will be nested), or when the specified + * file object in not representing a file (IOException will be + * nested) + * @see POST + * account/update_profile_image | Twitter Developers + * @since Twitter4J 2.1.11 + */ + User updateProfileImage(InputStream image) throws TwitterException; + + /** + * Returns an HTTP 200 OK response code and a representation of the + * requesting user if authentication was successful; returns a 401 status + * code and an error message if not. Use this method to test if supplied + * user credentials are valid.
+ * This method calls + * http://api.twitter.com/1.1/account/verify_credentials.json + * + * @return user + * @throws twitter4j.TwitterException when Twitter service or network is + * unavailable, or if supplied credential is wrong + * (TwitterException.getStatusCode() == 401) + * @see GET + * account/verify_credentials | Twitter Developers + * @since Twitter4J 2.0.0 + */ + User verifyCredentials() throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AccessToken.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AccessToken.java new file mode 100644 index 00000000..f55cfe6b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AccessToken.java @@ -0,0 +1,102 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.TwitterException; +import twitter4j.http.HttpResponse; + +/** + * Representing authorized Access Token which is passed to the service provider + * in order to access protected resources.
+ * the token and token secret can be stored into some persistent stores such as + * file system or RDBMS for the further accesses. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public class AccessToken extends OAuthToken { + private String screenName; + private long userId; + + public AccessToken(final String token, final String tokenSecret) { + super(token, tokenSecret); + String sUserId; + try { + sUserId = token.substring(0, token.indexOf("-")); + } catch (final IndexOutOfBoundsException e) { + throw new IllegalArgumentException("Invalid access token format."); + } + userId = Long.parseLong(sUserId); + } + + AccessToken(final HttpResponse res) throws TwitterException { + this(res.asString()); + } + + AccessToken(final String str) { + super(str); + screenName = getParameter("screen_name"); + final String sUserId = getParameter("user_id"); + if (sUserId != null) { + userId = Long.parseLong(sUserId); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + final AccessToken that = (AccessToken) o; + + if (userId != that.userId) return false; + if (screenName != null ? !screenName.equals(that.screenName) : that.screenName != null) return false; + + return true; + } + + /** + * @return screen name + * @since Twitter4J 2.0.4 + */ + + public String getScreenName() { + return screenName; + } + + /** + * @return user id + * @since Twitter4J 2.0.4 + */ + + public long getUserId() { + return userId; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (screenName != null ? screenName.hashCode() : 0); + result = 31 * result + (int) (userId ^ userId >>> 32); + return result; + } + + @Override + public String toString() { + return "AccessToken{" + "screenName='" + screenName + '\'' + ", userId=" + userId + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/Authorization.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/Authorization.java new file mode 100644 index 00000000..090b61d8 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/Authorization.java @@ -0,0 +1,36 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.http.HttpRequest; + +/** + * An interface represents credentials. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface Authorization { + + String getAuthorizationHeader(HttpRequest req); + + /** + * Returns true if authorization credentials are set. + * + * @return true if authorization credentials are set + */ + boolean isEnabled(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AuthorizationConfiguration.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AuthorizationConfiguration.java new file mode 100644 index 00000000..9aefa66d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AuthorizationConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +/** + * A static factory class for Authorization. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public interface AuthorizationConfiguration { + + String getOAuthAccessToken(); + + String getOAuthAccessTokenSecret(); + + String getOAuthConsumerKey(); + + String getOAuthConsumerSecret(); + + String getPassword(); + + String getUser(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AuthorizationFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AuthorizationFactory.java new file mode 100644 index 00000000..9987b19b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/AuthorizationFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.conf.Configuration; + +/** + * A static factory class for Authorization. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public final class AuthorizationFactory { + /** + * @param conf configuration + * @return authorization instance + * @since Twitter4J 2.1.11 + */ + public static Authorization getInstance(final Configuration conf) { + Authorization auth = null; + final String consumerKey = conf.getOAuthConsumerKey(); + final String consumerSecret = conf.getOAuthConsumerSecret(); + + if (consumerKey != null && consumerSecret != null) { + OAuthAuthorization oauth; + oauth = new OAuthAuthorization(conf); + final String accessToken = conf.getOAuthAccessToken(); + final String accessTokenSecret = conf.getOAuthAccessTokenSecret(); + if (accessToken != null && accessTokenSecret != null) { + oauth.setOAuthAccessToken(new AccessToken(accessToken, accessTokenSecret)); + } + auth = oauth; + } else { + final String screenName = conf.getUser(); + final String password = conf.getPassword(); + if (screenName != null && password != null) { + auth = new BasicAuthorization(screenName, password); + } + } + if (null == auth) { + auth = NullAuthorization.getInstance(); + } + return auth; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/BasicAuthorization.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/BasicAuthorization.java new file mode 100644 index 00000000..4deb3882 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/BasicAuthorization.java @@ -0,0 +1,88 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.http.BASE64Encoder; +import twitter4j.http.HttpRequest; + +/** + * An authentication implementation implements Basic authentication + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public class BasicAuthorization implements Authorization { + + private final String userId; + + private final String password; + private final String basic; + + public BasicAuthorization(final String userId, final String password) { + this.userId = userId; + this.password = password; + basic = encodeBasicAuthenticationString(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof BasicAuthorization)) return false; + + final BasicAuthorization that = (BasicAuthorization) o; + + return basic.equals(that.basic); + + } + + @Override + public String getAuthorizationHeader(final HttpRequest req) { + return basic; + } + + public String getPassword() { + return password; + } + + public String getUserId() { + return userId; + } + + @Override + public int hashCode() { + return basic.hashCode(); + } + + /** + * #{inheritDoc} + */ + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String toString() { + return "BasicAuthorization{" + "userId='" + userId + '\'' + ", password='**********'\'" + '}'; + } + + private String encodeBasicAuthenticationString() { + if (userId != null && password != null) + return "Basic " + BASE64Encoder.encode((userId + ":" + password).getBytes()); + return null; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/NullAuthorization.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/NullAuthorization.java new file mode 100644 index 00000000..01cf2ccd --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/NullAuthorization.java @@ -0,0 +1,66 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.auth; + +import java.io.ObjectStreamException; + +import twitter4j.http.HttpRequest; + +/** + * An interface represents credentials. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public class NullAuthorization implements Authorization { + private static NullAuthorization SINGLETON = new NullAuthorization(); + + private NullAuthorization() { + + } + + @Override + public boolean equals(final Object o) { + return SINGLETON == o; + } + + @Override + public String getAuthorizationHeader(final HttpRequest req) { + return null; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public String toString() { + return "NullAuthentication{SINGLETON}"; + } + + private Object readResolve() throws ObjectStreamException { + return SINGLETON; + } + + public static NullAuthorization getInstance() { + return SINGLETON; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthAuthorization.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthAuthorization.java new file mode 100644 index 00000000..525e19df --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthAuthorization.java @@ -0,0 +1,568 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.auth; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Random; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.BASE64Encoder; +import twitter4j.http.HttpClientWrapper; +import twitter4j.http.HttpParameter; +import twitter4j.http.HttpRequest; +import twitter4j.internal.logging.Logger; +import twitter4j.internal.util.InternalStringUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @see OAuth Core 1.0a + */ +public class OAuthAuthorization implements Authorization, OAuthSupport { + private final Configuration conf; + private transient static HttpClientWrapper http; + + private static final String HMAC_SHA1 = "HmacSHA1"; + private static final HttpParameter OAUTH_SIGNATURE_METHOD = new HttpParameter("oauth_signature_method", "HMAC-SHA1"); + private static final Logger logger = Logger.getLogger(OAuthAuthorization.class); + + private String consumerKey = ""; + private String consumerSecret; + + private String realm = null; + + private OAuthToken oauthToken = null; + + // constructors + + private static Random RAND = new Random(); + + /** + * @param conf configuration + */ + public OAuthAuthorization(final Configuration conf) { + this.conf = conf; + http = new HttpClientWrapper(conf); + setOAuthConsumer(conf.getOAuthConsumerKey(), conf.getOAuthConsumerSecret()); + if (conf.getOAuthAccessToken() != null && conf.getOAuthAccessTokenSecret() != null) { + setOAuthAccessToken(new AccessToken(conf.getOAuthAccessToken(), conf.getOAuthAccessTokenSecret())); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof OAuthSupport)) return false; + + final OAuthAuthorization that = (OAuthAuthorization) o; + + if (consumerKey != null ? !consumerKey.equals(that.consumerKey) : that.consumerKey != null) + return false; + if (consumerSecret != null ? !consumerSecret.equals(that.consumerSecret) : that.consumerSecret != null) + return false; + if (oauthToken != null ? !oauthToken.equals(that.oauthToken) : that.oauthToken != null) + return false; + + return true; + } + + public List generateOAuthSignatureHttpParams(final String method, final String sign_url) { + final long timestamp = System.currentTimeMillis() / 1000; + final long nonce = timestamp + RAND.nextInt(); + + final List oauthHeaderParams = new ArrayList(5); + oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); + oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); + oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); + oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); + oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); + if (oauthToken != null) { + oauthHeaderParams.add(new HttpParameter("oauth_token", oauthToken.getToken())); + } + + final List signatureBaseParams = new ArrayList(oauthHeaderParams.size()); + signatureBaseParams.addAll(oauthHeaderParams); + parseGetParameters(sign_url, signatureBaseParams); + + final StringBuffer base = new StringBuffer(method).append("&") + .append(HttpParameter.encode(constructRequestURL(sign_url))).append("&"); + base.append(HttpParameter.encode(normalizeRequestParameters(signatureBaseParams))); + + final String oauthBaseString = base.toString(); + final String signature = generateSignature(oauthBaseString, oauthToken); + + oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); + + return oauthHeaderParams; + } + + // implementation for OAuthSupport interface + + // implementations for Authorization + @Override + public String getAuthorizationHeader(final HttpRequest req) { + return generateAuthorizationHeader(req.getMethod().name(), req.getSignURL(), req.getParameters(), oauthToken); + } + + /** + * {@inheritDoc} + */ + @Override + public AccessToken getOAuthAccessToken() throws TwitterException { + ensureTokenIsAvailable(); + if (oauthToken instanceof AccessToken) return (AccessToken) oauthToken; + oauthToken = new AccessToken(http.post(conf.getOAuthAccessTokenURL(), conf.getSigningOAuthAccessTokenURL(), + this)); + return (AccessToken) oauthToken; + } + + /** + * {@inheritDoc} + */ + @Override + public AccessToken getOAuthAccessToken(final RequestToken requestToken) throws TwitterException { + oauthToken = requestToken; + return getOAuthAccessToken(); + } + + /** + * {@inheritDoc} + */ + @Override + public AccessToken getOAuthAccessToken(final RequestToken requestToken, final String oauthVerifier) + throws TwitterException { + oauthToken = requestToken; + return getOAuthAccessToken(oauthVerifier); + } + + /** + * {@inheritDoc} + */ + @Override + public AccessToken getOAuthAccessToken(final String oauthVerifier) throws TwitterException { + ensureTokenIsAvailable(); + final String url = conf.getOAuthAccessTokenURL(); + if (0 == url.indexOf("http://")) { + // SSL is required + // @see https://dev.twitter.com/docs/oauth/xauth + // url = "https://" + url.substring(7); + } + final String sign_url = conf.getSigningOAuthAccessTokenURL(); + if (0 == sign_url.indexOf("http://")) { + // SSL is required + // @see https://dev.twitter.com/docs/oauth/xauth + // sign_url = "https://" + sign_url.substring(7); + } + oauthToken = new AccessToken(http.post(url, sign_url, new HttpParameter[]{new HttpParameter("oauth_verifier", + oauthVerifier)}, this)); + return (AccessToken) oauthToken; + } + + /** + * {@inheritDoc} + */ + @Override + public AccessToken getOAuthAccessToken(final String screenName, final String password) throws TwitterException { + try { + final String url = conf.getOAuthAccessTokenURL(); + if (0 == url.indexOf("http://")) { + // SSL is required + // @see https://dev.twitter.com/docs/oauth/xauth + // url = "https://" + url.substring(7); + } + final String sign_url = conf.getSigningOAuthAccessTokenURL(); + if (0 == sign_url.indexOf("http://")) { + // SSL is required + // @see https://dev.twitter.com/docs/oauth/xauth + // sign_url = "https://" + sign_url.substring(7); + } + oauthToken = new AccessToken(http.post(url, sign_url, new HttpParameter[]{ + new HttpParameter("x_auth_username", screenName), new HttpParameter("x_auth_password", password), + new HttpParameter("x_auth_mode", "client_auth")}, this)); + return (AccessToken) oauthToken; + } catch (final TwitterException te) { + throw new TwitterException("The screen name / password combination seems to be invalid.", te, + te.getStatusCode()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public RequestToken getOAuthRequestToken() throws TwitterException { + return getOAuthRequestToken(null, null); + } + + /** + * {@inheritDoc} + */ + @Override + public RequestToken getOAuthRequestToken(final String callbackURL) throws TwitterException { + return getOAuthRequestToken(callbackURL, null); + } + + /** + * {@inheritDoc} + */ + @Override + public RequestToken getOAuthRequestToken(final String callbackURL, final String xAuthAccessType) + throws TwitterException { + if (oauthToken instanceof AccessToken) + throw new IllegalStateException("Access token already available."); + final List params = new ArrayList(); + if (callbackURL != null) { + params.add(new HttpParameter("oauth_callback", callbackURL)); + } + if (xAuthAccessType != null) { + params.add(new HttpParameter("x_auth_access_type", xAuthAccessType)); + } + final String url = conf.getOAuthRequestTokenURL(); + if (0 == url.indexOf("http://")) { + // SSL is required + // @see https://dev.twitter.com/docs/oauth/xauth + // url = "https://" + url.substring(7); + } + final String sign_url = conf.getSigningOAuthRequestTokenURL(); + if (0 == sign_url.indexOf("http://")) { + // SSL is required + // @see https://dev.twitter.com/docs/oauth/xauth + // sign_url = "https://" + sign_url.substring(7); + } + oauthToken = new RequestToken(conf, http.post(url, sign_url, params.toArray(new HttpParameter[params.size()]), + this), this); + return (RequestToken) oauthToken; + } + + @Override + public int hashCode() { + int result = consumerKey != null ? consumerKey.hashCode() : 0; + result = 31 * result + (consumerSecret != null ? consumerSecret.hashCode() : 0); + result = 31 * result + (oauthToken != null ? oauthToken.hashCode() : 0); + return result; + } + + /** + * #{inheritDoc} + */ + @Override + public boolean isEnabled() { + return oauthToken != null && oauthToken instanceof AccessToken; + } + + /** + * {@inheritDoc} + */ + @Override + public void setOAuthAccessToken(final AccessToken accessToken) { + oauthToken = accessToken; + } + + @Override + public void setOAuthConsumer(final String consumerKey, final String consumerSecret) { + this.consumerKey = consumerKey != null ? consumerKey : ""; + this.consumerSecret = consumerSecret != null ? consumerSecret : ""; + } + + /** + * Sets the OAuth realm + * + * @param realm OAuth realm + * @since Twitter 2.1.4 + */ + public void setOAuthRealm(final String realm) { + this.realm = realm; + } + + @Override + public String toString() { + return "OAuthAuthorization{" + "consumerKey='" + consumerKey + '\'' + + ", consumerSecret='******************************************\'" + ", oauthToken=" + oauthToken + '}'; + } + + private void ensureTokenIsAvailable() { + if (null == oauthToken) throw new IllegalStateException("No Token available."); + } + + /* package */ + + private void parseGetParameters(final String url, final List signatureBaseParams) { + final int queryStart = url.indexOf("?"); + if (-1 != queryStart) { + final String[] queryStrs = InternalStringUtil.split(url.substring(queryStart + 1), "&"); + try { + for (final String query : queryStrs) { + final String[] split = InternalStringUtil.split(query, "="); + if (split.length == 2) { + signatureBaseParams.add(new HttpParameter(URLDecoder.decode(split[0], "UTF-8"), URLDecoder + .decode(split[1], "UTF-8"))); + } else { + signatureBaseParams.add(new HttpParameter(URLDecoder.decode(split[0], "UTF-8"), "")); + } + } + } catch (final UnsupportedEncodingException ignore) { + } + + } + + } + + /** + * @return generated authorization header + * @see OAuth Core - + * 5.4.1. Authorization Header + */ + /* package */String generateAuthorizationHeader(final String method, final String sign_url, + final HttpParameter[] params, final OAuthToken token) { + final long timestamp = System.currentTimeMillis() / 1000; + final long nonce = timestamp + RAND.nextInt(); + return generateAuthorizationHeader(method, sign_url, params, String.valueOf(nonce), String.valueOf(timestamp), + token); + } + + /* package */String generateAuthorizationHeader(final String method, final String sign_url, HttpParameter[] params, + final String nonce, final String timestamp, final OAuthToken otoken) { + if (null == params) { + params = new HttpParameter[0]; + } + final List oauthHeaderParams = new ArrayList(5); + oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); + oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); + oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); + oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); + oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); + if (otoken != null) { + oauthHeaderParams.add(new HttpParameter("oauth_token", otoken.getToken())); + } + final List signatureBaseParams = new ArrayList(oauthHeaderParams.size() + + params.length); + signatureBaseParams.addAll(oauthHeaderParams); + if (!HttpParameter.containsFile(params)) { + signatureBaseParams.addAll(toParamList(params)); + } + parseGetParameters(sign_url, signatureBaseParams); + final StringBuffer base = new StringBuffer(method).append("&") + .append(HttpParameter.encode(constructRequestURL(sign_url))).append("&"); + base.append(HttpParameter.encode(normalizeRequestParameters(signatureBaseParams))); + final String oauthBaseString = base.toString(); + logger.debug("OAuth base string: ", oauthBaseString); + final String signature = generateSignature(oauthBaseString, otoken); + logger.debug("OAuth signature: ", signature); + + oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); + + // http://oauth.net/core/1.0/#rfc.section.9.1.1 + if (realm != null) { + oauthHeaderParams.add(new HttpParameter("realm", realm)); + } + return "OAuth " + encodeParameters(oauthHeaderParams, ",", true); + } + + String generateSignature(final String data) { + return generateSignature(data, null); + } + + /** + * Computes RFC 2104-compliant HMAC signature. + * + * @param data the data to be signed + * @param token the token + * @return signature + * @see OAuth Core - + * 9.2.1. Generating Signature + */ + /* package */String generateSignature(final String data, final OAuthToken token) { + byte[] byteHMAC = null; + try { + final Mac mac = Mac.getInstance(HMAC_SHA1); + SecretKeySpec spec; + if (null == token) { + final String oauthSignature = HttpParameter.encode(consumerSecret) + "&"; + spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); + } else { + spec = token.getSecretKeySpec(); + if (null == spec) { + final String oauthSignature = HttpParameter.encode(consumerSecret) + "&" + + HttpParameter.encode(token.getTokenSecret()); + spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); + token.setSecretKeySpec(spec); + } + } + mac.init(spec); + byteHMAC = mac.doFinal(data.getBytes()); + } catch (final InvalidKeyException ike) { + logger.error("Failed initialize \"Message Authentication Code\" (MAC)", ike); + throw new AssertionError(ike); + } catch (final NoSuchAlgorithmException nsae) { + logger.error("Failed to get HmacSHA1 \"Message Authentication Code\" (MAC)", nsae); + throw new AssertionError(nsae); + } + return BASE64Encoder.encode(byteHMAC); + } + + /** + * The Signature Base String includes the request absolute URL, tying the + * signature to a specific endpoint. The URL used in the Signature Base + * String MUST include the scheme, authority, and path, and MUST exclude the + * query and fragment as defined by [RFC3986] section 3.
+ * If the absolute request URL is not available to the Service Provider (it + * is always available to the Consumer), it can be constructed by combining + * the scheme being used, the HTTP Host header, and the relative HTTP + * request URL. If the Host header is not available, the Service Provider + * SHOULD use the host name communicated to the Consumer in the + * documentation or other means.
+ * The Service Provider SHOULD document the form of URL used in the + * Signature Base String to avoid ambiguity due to URL normalization. Unless + * specified, URL scheme and authority MUST be lowercase and include the + * port number; http default port 80 and https default port 443 MUST be + * excluded.
+ *
+ * For example, the request:
+ * HTTP://Example.com:80/resource?id=123
+ * Is included in the Signature Base String as:
+ * http://example.com/resource + * + * @param url the url to be normalized + * @return the Signature Base String + * @see OAuth Core - + * 9.1.2. Construct Request URL + */ + public static String constructRequestURL(String url) { + final int index = url.indexOf("?"); + if (-1 != index) { + url = url.substring(0, index); + } + final int slashIndex = url.indexOf("/", 8); + String baseURL = url.substring(0, slashIndex).toLowerCase(Locale.US); + final int colonIndex = baseURL.indexOf(":", 8); + if (-1 != colonIndex) { + // url contains port number + if (baseURL.startsWith("http://") && baseURL.endsWith(":80")) { + // http default port 80 MUST be excluded + baseURL = baseURL.substring(0, colonIndex); + } else if (baseURL.startsWith("https://") && baseURL.endsWith(":443")) { + // http default port 443 MUST be excluded + baseURL = baseURL.substring(0, colonIndex); + } + } + url = baseURL + url.substring(slashIndex); + + return url; + } + + /** + * @param httpParams parameters to be encoded and concatenated + * @return encoded string + * @see OAuth / TestCases + * @see Space + * encoding - OAuth | Google Groups + */ + public static String encodeParameters(final List httpParams) { + return encodeParameters(httpParams, "&", false); + } + + public static String encodeParameters(final List httpParams, final String splitter, + final boolean quot) { + final StringBuffer buf = new StringBuffer(); + for (final HttpParameter param : httpParams) { + if (!param.isFile()) { + if (buf.length() != 0) { + if (quot) { + buf.append("\""); + } + buf.append(splitter); + } + buf.append(HttpParameter.encode(param.getName())).append("="); + if (quot) { + buf.append("\""); + } + buf.append(HttpParameter.encode(param.getValue())); + } + } + if (buf.length() != 0) { + if (quot) { + buf.append("\""); + } + } + return buf.toString(); + } + + public static String normalizeAuthorizationHeaders(final List params) { + Collections.sort(params); + return encodeParameters(params); + } + + /** + * The request parameters are collected, sorted and concatenated into a + * normalized string:
+ * • Parameters in the OAuth HTTP Authorization header excluding the realm + * parameter.
+ * • Parameters in the HTTP POST request body (with a content-type of + * application/x-www-form-urlencoded).
+ * • HTTP GET parameters added to the URLs in the query part (as defined by + * [RFC3986] section 3).
+ *
+ * The oauth_signature parameter MUST be excluded.
+ * The parameters are normalized into a single string as follows:
+ * 1. Parameters are sorted by name, using lexicographical byte value + * ordering. If two or more parameters share the same name, they are sorted + * by their value. For example:
+ * 2. a=1, c=hi%20there, f=25, f=50, f=a, z=p, z=t
+ * 3.
+ * 4. Parameters are concatenated in their sorted order into a single + * string. For each parameter, the name is separated from the corresponding + * value by an ‘=’ character (ASCII code 61), even if the value is empty. + * Each name-value pair is separated by an ‘&’ character (ASCII code 38). + * For example:
+ * 5. a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t
+ * 6.
+ * + * @param params parameters to be normalized and concatenated + * @return normalized and concatenated parameters + * @see OAuth Core - + * 9.1.1. Normalize Request Parameters + */ + public static String normalizeRequestParameters(final HttpParameter[] params) { + return normalizeRequestParameters(toParamList(params)); + } + + public static String normalizeRequestParameters(final List params) { + Collections.sort(params); + return encodeParameters(params); + } + + public static List toParamList(final HttpParameter[] params) { + final List paramList = new ArrayList(params.length); + paramList.addAll(Arrays.asList(params)); + return paramList; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthSupport.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthSupport.java new file mode 100644 index 00000000..fdc86145 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthSupport.java @@ -0,0 +1,191 @@ +package twitter4j.auth; + +import twitter4j.TwitterException; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.0 + */ +public interface OAuthSupport { + /** + * Returns an access token associated with this instance.
+ * If no access token is associated with this instance, this will retrieve a + * new access token. + * + * @return access token + * @throws TwitterException when Twitter service or network is unavailable, + * or the user has not authorized + * @throws IllegalStateException when RequestToken has never been acquired + * @see OAuth FAQ | + * dev.twitter.com - How long does an access token last? + * @see OAuth Core 1.0a - + * 6.2. Obtaining User Authorization + * @see POST + * oauth/access_token | Twitter Developers + * @since Twitter4J 2.0.0 + */ + AccessToken getOAuthAccessToken() throws TwitterException; + + /** + * Retrieves an access token associated with the supplied request token and + * sets userId. + * + * @param requestToken the request token + * @return access token associated with the supplied request token. + * @throws TwitterException when Twitter service or network is unavailable, + * or the user has not authorized + * @see OAuth FAQ | + * dev.twitter.com - How long does an access token last? + * @see OAuth Core 1.0a - + * 6.2. Obtaining User Authorization + * @see POST + * oauth/access_token | Twitter Developers + * @since Twitter4J 2.0.0 + */ + AccessToken getOAuthAccessToken(RequestToken requestToken) throws TwitterException; + + /** + * Retrieves an access token associated with the supplied request token and + * sets userId. + * + * @param requestToken the request token + * @param oauthVerifier OAuth verifier. AKA pin. + * @return access token associated with the supplied request token. + * @throws TwitterException when Twitter service or network is unavailable, + * or the user has not authorized + * @see OAuth Core 1.0a - + * 6.2. Obtaining User Authorization + * @see POST + * oauth/access_token | Twitter Developers + * @since Twitter 2.1.1 + */ + AccessToken getOAuthAccessToken(RequestToken requestToken, String oauthVerifier) throws TwitterException; + + /** + * Retrieves an access token. + * + * @param oauthVerifier OAuth verifier. AKA pin. + * @return access token + * @throws TwitterException when Twitter service or network is unavailable, + * or the user has not authorized + * @see OAuth FAQ | + * dev.twitter.com - How long does an access token last? + * @see OAuth Core 1.0a - + * 6.2. Obtaining User Authorization + * @see POST + * oauth/access_token | Twitter Developers + * @since Twitter4J 2.0.0 + */ + AccessToken getOAuthAccessToken(String oauthVerifier) throws TwitterException; + + /** + * Retrieves an access token associated with the supplied screen name and + * password using xAuth.
+ * In order to get access acquire AccessToken using xAuth, you must apply by + * sending an email to api@twitter.com — all other applications will receive + * an HTTP 401 error. Web-based applications will not be granted access, + * except on a temporary basis for when they are converting from + * basic-authentication support to full OAuth support.
+ * Storage of Twitter usernames and passwords is forbidden. By using xAuth, + * you are required to store only access tokens and access token secrets. If + * the access token expires or is expunged by a user, you must ask for their + * login and password again before exchanging the credentials for an access + * token. + * + * @param screenName the screen name + * @param password the password + * @return access token associated with the supplied request token. + * @throws TwitterException when Twitter service or network is unavailable, + * or the user has not authorized + * @see OAuth FAQ | + * dev.twitter.com - How long does an access token last? + * @see xAuth | Twitter + * Developers + * @see POST + * oauth/access_token | Twitter Developers + * @since Twitter 2.1.1 + */ + AccessToken getOAuthAccessToken(String screenName, String password) throws TwitterException; + + /** + * Retrieves a request token + * + * @return generated request token. + * @throws TwitterException when Twitter service or network is unavailable + * @throws IllegalStateException access token is already available + * @see OAuth FAQ | + * Twitter Developers + * @see OAuth Core 1.0a - + * 6.1. Obtaining an Unauthorized Request Token + * @see POST + * oauth/request_token | Twitter Developers + * @since Twitter4J 2.0.0 + */ + RequestToken getOAuthRequestToken() throws TwitterException; + + /** + * Retrieves a request token + * + * @param callbackURL callback URL + * @return generated request token + * @throws TwitterException when Twitter service or network is unavailable + * @throws IllegalStateException access token is already available + * @see OAuth FAQ | + * Twitter Developers + * @see OAuth Core 1.0a - + * 6.1. Obtaining an Unauthorized Request Token + * @see POST + * oauth/request_token | Twitter Developers + * @since Twitter4J 2.0.0 + */ + RequestToken getOAuthRequestToken(String callbackURL) throws TwitterException; + + /** + * Retrieves a request token + * + * @param callbackURL callback URL + * @param xAuthAccessType Overrides the access level an application requests + * to a users account. Supported values are read or write. This + * parameter is intended to allow a developer to register a + * read/write application but also request read only access when + * appropriate. + * @return generated request token + * @throws TwitterException when Twitter service or network is unavailable + * @throws IllegalStateException access token is already available + * @see OAuth FAQ | + * Twitter Developers + * @see OAuth Core 1.0a - + * 6.1. Obtaining an Unauthorized Request Token + * @see POST + * oauth/request_token | Twitter Developers + * @since Twitter4J 2.2.3 + */ + RequestToken getOAuthRequestToken(String callbackURL, String xAuthAccessType) throws TwitterException; + + /** + * Sets the access token + * + * @param accessToken accessToken + * @since Twitter4J 2.0.0 + */ + void setOAuthAccessToken(AccessToken accessToken); + + /** + * sets the OAuth consumer key and consumer secret + * + * @param consumerKey OAuth consumer key + * @param consumerSecret OAuth consumer secret + * @throws IllegalStateException when OAuth consumer has already been set, + * or the instance is using basic authorization + * @since Twitter 2.0.0 + */ + void setOAuthConsumer(String consumerKey, String consumerSecret); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthToken.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthToken.java new file mode 100644 index 00000000..13bb4f65 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/OAuthToken.java @@ -0,0 +1,103 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.auth; + +import javax.crypto.spec.SecretKeySpec; + +import twitter4j.TwitterException; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalStringUtil; + +abstract class OAuthToken { + + private final String token; + private final String tokenSecret; + + private transient SecretKeySpec secretKeySpec; + String[] responseStr = null; + + public OAuthToken(final String token, final String tokenSecret) { + this.token = token; + this.tokenSecret = tokenSecret; + } + + OAuthToken(final HttpResponse response) throws TwitterException { + this(response.asString()); + } + + OAuthToken(final String string) { + responseStr = InternalStringUtil.split(string, "&"); + tokenSecret = getParameter("oauth_token_secret"); + token = getParameter("oauth_token"); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof OAuthToken)) return false; + + final OAuthToken that = (OAuthToken) o; + + if (!token.equals(that.token)) return false; + if (!tokenSecret.equals(that.tokenSecret)) return false; + + return true; + } + + public String getParameter(final String parameter) { + String value = null; + for (final String str : responseStr) { + if (str.startsWith(parameter + '=')) { + value = InternalStringUtil.split(str, "=")[1].trim(); + break; + } + } + return value; + } + + public String getToken() { + return token; + } + + public String getTokenSecret() { + return tokenSecret; + } + + @Override + public int hashCode() { + int result = token.hashCode(); + result = 31 * result + tokenSecret.hashCode(); + return result; + } + + @Override + public String toString() { + return "OAuthToken{" + "token='" + token + '\'' + ", tokenSecret='" + tokenSecret + '\'' + ", secretKeySpec=" + + secretKeySpec + '}'; + } + + /* package */SecretKeySpec getSecretKeySpec() { + return secretKeySpec; + } + + /* package */void setSecretKeySpec(final SecretKeySpec secretKeySpec) { + this.secretKeySpec = secretKeySpec; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/RequestToken.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/RequestToken.java new file mode 100644 index 00000000..10dbad93 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/RequestToken.java @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.conf.ConfigurationContext; +import twitter4j.http.HttpResponse; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com representing unauthorized Request + * Token which is passed to the service provider when acquiring the + * authorized Access Token + */ +public final class RequestToken extends OAuthToken { + private final Configuration conf; + + public RequestToken(final Configuration conf, final String token, final String tokenSecret) { + super(token, tokenSecret); + this.conf = conf; + } + + @Deprecated + public RequestToken(final String token, final String tokenSecret) { + super(token, tokenSecret); + conf = ConfigurationContext.getInstance(); + } + + RequestToken(final Configuration conf, final HttpResponse res, final OAuthSupport oauth) throws TwitterException { + super(res); + this.conf = conf; + } + + RequestToken(final Configuration conf, final String token, final String tokenSecret, final OAuthSupport oauth) { + super(token, tokenSecret); + this.conf = conf; + } + + @Deprecated + RequestToken(final HttpResponse res, final OAuthSupport oauth) throws TwitterException { + super(res); + conf = ConfigurationContext.getInstance(); + } + + @Deprecated + RequestToken(final String token, final String tokenSecret, final OAuthSupport oauth) { + super(token, tokenSecret); + conf = ConfigurationContext.getInstance(); + } + + /** + * @return authentication URL since Twitter4J 2.0.10 + */ + public String getAuthenticationURL() { + return conf.getOAuthAuthenticationURL() + "?oauth_token=" + getToken(); + } + + /** + * @return authorization URL since Twitter4J 2.0.0 + */ + public String getAuthorizationURL() { + return conf.getOAuthAuthorizationURL() + "?oauth_token=" + getToken(); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/TwipOModeAuthorization.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/TwipOModeAuthorization.java new file mode 100644 index 00000000..65fb4f91 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/TwipOModeAuthorization.java @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.http.HttpRequest; + +/** + * An interface represents credentials. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public class TwipOModeAuthorization implements Authorization { + + private static TwipOModeAuthorization SINGLETON = new TwipOModeAuthorization(); + + public TwipOModeAuthorization() { + + } + + @Override + public boolean equals(final Object o) { + return SINGLETON == o; + } + + @Override + public String getAuthorizationHeader(final HttpRequest req) { + return null; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String toString() { + return "TwipOModeAuthentication{SINGLETON}"; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/auth/XAuthAuthorization.java b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/XAuthAuthorization.java new file mode 100644 index 00000000..845e40a9 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/auth/XAuthAuthorization.java @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.auth; + +import twitter4j.http.HttpRequest; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +public class XAuthAuthorization implements Authorization { + private final BasicAuthorization basic; + + private String consumerKey; + private String consumerSecret; + + public XAuthAuthorization(final BasicAuthorization basic) { + this.basic = basic; + } + + @Override + public String getAuthorizationHeader(final HttpRequest req) { + return basic.getAuthorizationHeader(req); + } + + public String getConsumerKey() { + return consumerKey; + } + + public String getConsumerSecret() { + return consumerSecret; + } + + public String getPassword() { + return basic.getPassword(); + } + + public String getUserId() { + return basic.getUserId(); + } + + @Override + public boolean isEnabled() { + return basic.isEnabled(); + } + + public synchronized void setOAuthConsumer(final String consumerKey, final String consumerSecret) { + this.consumerKey = consumerKey; + this.consumerSecret = consumerSecret; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/conf/BaseConfigurationFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/BaseConfigurationFactory.java new file mode 100644 index 00000000..3240d44b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/BaseConfigurationFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +/** + * ConfigurationFactory implementation for ConfigurationBase. Currently + * getInstance calls concrete constructor each time. No caching at all. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +class BaseConfigurationFactory implements ConfigurationFactory { + private static final ConfigurationBase ROOT_CONFIGURATION; + + static { + ROOT_CONFIGURATION = new ConfigurationBase(); + } + + /** + * {@inheritDoc} + */ + @Override + public void dispose() { + // nothing to do for property based configuration + } + + // It may be preferable to cache the config instance + + /** + * {@inheritDoc} + */ + @Override + public Configuration getInstance() { + return ROOT_CONFIGURATION; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/conf/Configuration.java b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/Configuration.java new file mode 100644 index 00000000..6c6c2caa --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/Configuration.java @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +import twitter4j.auth.AuthorizationConfiguration; +import twitter4j.http.HttpClientConfiguration; +import twitter4j.http.HttpClientWrapperConfiguration; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface Configuration extends HttpClientConfiguration, HttpClientWrapperConfiguration, + AuthorizationConfiguration { + + String getCardsPlatform(); + + String getClientName(); + + String getClientURL(); + + String getClientVersion(); + + String getOAuthAccessTokenURL(); + + String getOAuthAuthenticationURL(); + + String getOAuthAuthorizationURL(); + + String getOAuthBaseURL(); + + String getOAuthRequestTokenURL(); + + String getRestBaseURL(); + + String getSigningOAuthAccessTokenURL(); + + String getSigningOAuthAuthenticationURL(); + + String getSigningOAuthAuthorizationURL(); + + String getSigningOAuthBaseURL(); + + String getSigningOAuthRequestTokenURL(); + + String getSigningRestBaseURL(); + + String getSigningUploadBaseURL(); + + String getUploadBaseURL(); + + boolean isDebugEnabled(); + + boolean isIncludeCardsEnabled(); + + boolean isIncludeEntitiesEnabled(); + + boolean isIncludeRTsEnabled(); + + boolean isIncludeReplyCountEnabled(); + + boolean isIncludeDescendentReplyCountEnabled(); + + boolean isTwitterClientHeaderIncluded(); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationBase.java b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationBase.java new file mode 100644 index 00000000..5d1c449c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationBase.java @@ -0,0 +1,936 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +import java.io.ObjectStreamException; +import java.util.ArrayList; +import java.util.List; + +import twitter4j.TwitterConstants; +import twitter4j.Version; +import twitter4j.http.HeaderMap; +import twitter4j.http.HostAddressResolverFactory; +import twitter4j.http.HttpClientFactory; + +/** + * Configuration base class with default settings. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +class ConfigurationBase implements TwitterConstants, Configuration { + + static final boolean DEFAULT_USE_SSL = true; + + private boolean debug; + private String userAgent; + private String user; + private String password; + private boolean useSSL; + private boolean ignoreSSLError; + private boolean prettyDebug; + private boolean gzipEnabled; + private String httpProxyHost; + private String httpProxyUser; + private String httpProxyPassword; + private int httpProxyPort; + private int httpConnectionTimeout; + private int httpReadTimeout; + + private int httpRetryCount; + private int httpRetryIntervalSeconds; + private int maxTotalConnections; + private int defaultMaxPerRoute; + private String oAuthConsumerKey; + private String oAuthConsumerSecret; + private String oAuthAccessToken; + private String oAuthAccessTokenSecret; + + private String oAuthRequestTokenURL; + private String oAuthAuthorizationURL; + private String oAuthAccessTokenURL; + private String oAuthAuthenticationURL; + + private String signingOAuthRequestTokenURL; + private String signingOAuthAuthorizationURL; + private String signingOAuthAccessTokenURL; + private String signingOAuthAuthenticationURL; + + private String oAuthBaseURL = DEFAULT_OAUTH_BASE_URL; + + private String signingOAuthBaseURL; + private String signingRestBaseURL; + private String signingUploadBaseURL; + + private String restBaseURL; + private String uploadBaseURL; + + private boolean includeRTsEnabled; + + private boolean includeReplyCountEnabled; + + private boolean includeDescendentReplyCountEnabled; + + private boolean includeEntitiesEnabled; + + private boolean includeTwitterClientHeader; + + // hidden portion + private String clientVersion; + private String clientURL; + private String clientName; + + private HttpClientFactory httpClientFactory; + private HostAddressResolverFactory hostAddressResolverFactory; + + // method for HttpRequestFactoryConfiguration + HeaderMap requestHeaders; + + private static final List instances = new ArrayList(); + private boolean includeCards; + private String cardsPlatform; + + protected ConfigurationBase() { + setDebug(false); + setUser(null); + setPassword(null); + setUseSSL(false); + setPrettyDebugEnabled(false); + setGZIPEnabled(true); + setHttpProxyHost(null); + setHttpProxyUser(null); + setHttpProxyPassword(null); + setHttpProxyPort(-1); + setHttpConnectionTimeout(20000); + setHttpReadTimeout(120000); + setHttpRetryCount(0); + setHttpRetryIntervalSeconds(5); + setHttpMaxTotalConnections(20); + setHttpDefaultMaxPerRoute(2); + setHttpClientFactory(null); + setOAuthConsumerKey(null); + setOAuthConsumerSecret(null); + setOAuthAccessToken(null); + setOAuthAccessTokenSecret(null); + setClientName("Twitter4J"); + setClientVersion(Version.getVersion()); + setClientURL("http://twitter4j.org/en/twitter4j-" + Version.getVersion() + ".xml"); + setHttpUserAgent("twitter4j http://twitter4j.org/ /" + Version.getVersion()); + + setIncludeRTsEnabled(true); + + setIncludeEntitiesEnabled(true); + + setOAuthBaseURL(DEFAULT_OAUTH_BASE_URL); + setSigningOAuthBaseURL(DEFAULT_SIGNING_OAUTH_BASE_URL); + + setRestBaseURL(DEFAULT_REST_BASE_URL); + setSigningRestBaseURL(DEFAULT_SIGNING_REST_BASE_URL); + + setUploadBaseURL(DEFAULT_UPLOAD_BASE_URL); + setSigningUploadBaseURL(DEFAULT_SIGNING_UPLOAD_BASE_URL); + setIncludeRTsEnabled(true); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ConfigurationBase)) return false; + final ConfigurationBase other = (ConfigurationBase) obj; + if (clientName == null) { + if (other.clientName != null) return false; + } else if (!clientName.equals(other.clientName)) return false; + if (clientURL == null) { + if (other.clientURL != null) return false; + } else if (!clientURL.equals(other.clientURL)) return false; + if (clientVersion == null) { + if (other.clientVersion != null) return false; + } else if (!clientVersion.equals(other.clientVersion)) return false; + if (debug != other.debug) return false; + if (defaultMaxPerRoute != other.defaultMaxPerRoute) return false; + if (gzipEnabled != other.gzipEnabled) return false; + if (hostAddressResolverFactory == null) { + if (other.hostAddressResolverFactory != null) return false; + } else if (!hostAddressResolverFactory.equals(other.hostAddressResolverFactory)) + return false; + if (httpClientFactory == null) { + if (other.httpClientFactory != null) return false; + } else if (!httpClientFactory.equals(other.httpClientFactory)) return false; + if (httpConnectionTimeout != other.httpConnectionTimeout) return false; + if (httpProxyHost == null) { + if (other.httpProxyHost != null) return false; + } else if (!httpProxyHost.equals(other.httpProxyHost)) return false; + if (httpProxyPassword == null) { + if (other.httpProxyPassword != null) return false; + } else if (!httpProxyPassword.equals(other.httpProxyPassword)) return false; + if (httpProxyPort != other.httpProxyPort) return false; + if (httpProxyUser == null) { + if (other.httpProxyUser != null) return false; + } else if (!httpProxyUser.equals(other.httpProxyUser)) return false; + if (httpReadTimeout != other.httpReadTimeout) return false; + if (httpRetryCount != other.httpRetryCount) return false; + if (httpRetryIntervalSeconds != other.httpRetryIntervalSeconds) return false; + if (ignoreSSLError != other.ignoreSSLError) return false; + if (includeEntitiesEnabled != other.includeEntitiesEnabled) return false; + if (includeRTsEnabled != other.includeRTsEnabled) return false; + if (includeTwitterClientHeader != other.includeTwitterClientHeader) return false; + if (maxTotalConnections != other.maxTotalConnections) return false; + if (oAuthAccessToken == null) { + if (other.oAuthAccessToken != null) return false; + } else if (!oAuthAccessToken.equals(other.oAuthAccessToken)) return false; + if (oAuthAccessTokenSecret == null) { + if (other.oAuthAccessTokenSecret != null) return false; + } else if (!oAuthAccessTokenSecret.equals(other.oAuthAccessTokenSecret)) return false; + if (oAuthAccessTokenURL == null) { + if (other.oAuthAccessTokenURL != null) return false; + } else if (!oAuthAccessTokenURL.equals(other.oAuthAccessTokenURL)) return false; + if (oAuthAuthenticationURL == null) { + if (other.oAuthAuthenticationURL != null) return false; + } else if (!oAuthAuthenticationURL.equals(other.oAuthAuthenticationURL)) return false; + if (oAuthAuthorizationURL == null) { + if (other.oAuthAuthorizationURL != null) return false; + } else if (!oAuthAuthorizationURL.equals(other.oAuthAuthorizationURL)) return false; + if (oAuthBaseURL == null) { + if (other.oAuthBaseURL != null) return false; + } else if (!oAuthBaseURL.equals(other.oAuthBaseURL)) return false; + if (oAuthConsumerKey == null) { + if (other.oAuthConsumerKey != null) return false; + } else if (!oAuthConsumerKey.equals(other.oAuthConsumerKey)) return false; + if (oAuthConsumerSecret == null) { + if (other.oAuthConsumerSecret != null) return false; + } else if (!oAuthConsumerSecret.equals(other.oAuthConsumerSecret)) return false; + if (oAuthRequestTokenURL == null) { + if (other.oAuthRequestTokenURL != null) return false; + } else if (!oAuthRequestTokenURL.equals(other.oAuthRequestTokenURL)) return false; + if (password == null) { + if (other.password != null) return false; + } else if (!password.equals(other.password)) return false; + if (prettyDebug != other.prettyDebug) return false; + if (requestHeaders == null) { + if (other.requestHeaders != null) return false; + } else if (!requestHeaders.equals(other.requestHeaders)) return false; + if (restBaseURL == null) { + if (other.restBaseURL != null) return false; + } else if (!restBaseURL.equals(other.restBaseURL)) return false; + if (signingOAuthAccessTokenURL == null) { + if (other.signingOAuthAccessTokenURL != null) return false; + } else if (!signingOAuthAccessTokenURL.equals(other.signingOAuthAccessTokenURL)) + return false; + if (signingOAuthAuthenticationURL == null) { + if (other.signingOAuthAuthenticationURL != null) return false; + } else if (!signingOAuthAuthenticationURL.equals(other.signingOAuthAuthenticationURL)) + return false; + if (signingOAuthAuthorizationURL == null) { + if (other.signingOAuthAuthorizationURL != null) return false; + } else if (!signingOAuthAuthorizationURL.equals(other.signingOAuthAuthorizationURL)) + return false; + if (signingOAuthBaseURL == null) { + if (other.signingOAuthBaseURL != null) return false; + } else if (!signingOAuthBaseURL.equals(other.signingOAuthBaseURL)) return false; + if (signingOAuthRequestTokenURL == null) { + if (other.signingOAuthRequestTokenURL != null) return false; + } else if (!signingOAuthRequestTokenURL.equals(other.signingOAuthRequestTokenURL)) + return false; + if (signingRestBaseURL == null) { + if (other.signingRestBaseURL != null) return false; + } else if (!signingRestBaseURL.equals(other.signingRestBaseURL)) return false; + if (useSSL != other.useSSL) return false; + if (user == null) { + if (other.user != null) return false; + } else if (!user.equals(other.user)) return false; + if (userAgent == null) { + if (other.userAgent != null) return false; + } else if (!userAgent.equals(other.userAgent)) return false; + return true; + } + + public String getCardsPlatform() { + return cardsPlatform; + } + + @Override + public final String getClientName() { + return clientName; + } + + @Override + public final String getClientURL() { + return clientURL; + } + + @Override + public final String getClientVersion() { + return clientVersion; + } + + @Override + public HostAddressResolverFactory getHostAddressResolverFactory() { + return hostAddressResolverFactory; + } + + @Override + public HttpClientFactory getHttpClientFactory() { + return httpClientFactory; + } + + @Override + public final int getHttpConnectionTimeout() { + return httpConnectionTimeout; + } + + @Override + public final int getHttpDefaultMaxPerRoute() { + return defaultMaxPerRoute; + } + + @Override + public final int getHttpMaxTotalConnections() { + return maxTotalConnections; + } + + @Override + public final String getHttpProxyHost() { + return httpProxyHost; + } + + @Override + public final String getHttpProxyPassword() { + return httpProxyPassword; + } + + @Override + public final int getHttpProxyPort() { + return httpProxyPort; + } + + @Override + public final String getHttpProxyUser() { + return httpProxyUser; + } + + @Override + public final int getHttpReadTimeout() { + return httpReadTimeout; + } + + @Override + public final int getHttpRetryCount() { + return httpRetryCount; + } + + @Override + public final int getHttpRetryIntervalSeconds() { + return httpRetryIntervalSeconds; + } + + @Override + public final String getHttpUserAgent() { + return userAgent; + } + + @Override + public String getOAuthAccessToken() { + return oAuthAccessToken; + } + + @Override + public String getOAuthAccessTokenSecret() { + return oAuthAccessTokenSecret; + } + + @Override + public String getOAuthAccessTokenURL() { + return oAuthAccessTokenURL; + } + + @Override + public String getOAuthAuthenticationURL() { + return oAuthAuthenticationURL; + } + + @Override + public String getOAuthAuthorizationURL() { + return oAuthAuthorizationURL; + } + + @Override + public String getOAuthBaseURL() { + return oAuthBaseURL; + } + + @Override + public final String getOAuthConsumerKey() { + return oAuthConsumerKey; + } + + @Override + public final String getOAuthConsumerSecret() { + return oAuthConsumerSecret; + } + + @Override + public String getOAuthRequestTokenURL() { + return oAuthRequestTokenURL; + } + + @Override + public final String getPassword() { + return password; + } + + @Override + public HeaderMap getRequestHeaders() { + return requestHeaders; + } + + @Override + public String getRestBaseURL() { + return restBaseURL; + } + + @Override + public String getSigningOAuthAccessTokenURL() { + return signingOAuthAccessTokenURL != null ? signingOAuthAccessTokenURL : oAuthAccessTokenURL; + } + + @Override + public String getSigningOAuthAuthenticationURL() { + return signingOAuthAuthenticationURL != null ? signingOAuthAuthenticationURL : oAuthAuthenticationURL; + } + + @Override + public String getSigningOAuthAuthorizationURL() { + return signingOAuthAuthorizationURL != null ? signingOAuthAuthorizationURL : oAuthAuthorizationURL; + } + + @Override + public String getSigningOAuthBaseURL() { + return signingOAuthBaseURL != null ? signingOAuthBaseURL : oAuthBaseURL; + } + + @Override + public String getSigningOAuthRequestTokenURL() { + return signingOAuthRequestTokenURL != null ? signingOAuthRequestTokenURL : oAuthRequestTokenURL; + } + + @Override + public String getSigningRestBaseURL() { + return signingRestBaseURL != null ? signingRestBaseURL : restBaseURL; + } + + @Override + public String getSigningUploadBaseURL() { + return signingUploadBaseURL != null ? signingUploadBaseURL : uploadBaseURL; + } + + @Override + public String getUploadBaseURL() { + return uploadBaseURL; + } + + @Override + public final String getUser() { + return user; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (clientName == null ? 0 : clientName.hashCode()); + result = prime * result + (clientURL == null ? 0 : clientURL.hashCode()); + result = prime * result + (clientVersion == null ? 0 : clientVersion.hashCode()); + result = prime * result + (debug ? 1231 : 1237); + result = prime * result + defaultMaxPerRoute; + result = prime * result + (gzipEnabled ? 1231 : 1237); + result = prime * result + (hostAddressResolverFactory == null ? 0 : hostAddressResolverFactory.hashCode()); + result = prime * result + (httpClientFactory == null ? 0 : httpClientFactory.hashCode()); + result = prime * result + httpConnectionTimeout; + result = prime * result + (httpProxyHost == null ? 0 : httpProxyHost.hashCode()); + result = prime * result + (httpProxyPassword == null ? 0 : httpProxyPassword.hashCode()); + result = prime * result + httpProxyPort; + result = prime * result + (httpProxyUser == null ? 0 : httpProxyUser.hashCode()); + result = prime * result + httpReadTimeout; + result = prime * result + httpRetryCount; + result = prime * result + httpRetryIntervalSeconds; + result = prime * result + (ignoreSSLError ? 1231 : 1237); + result = prime * result + (includeEntitiesEnabled ? 1231 : 1237); + result = prime * result + (includeRTsEnabled ? 1231 : 1237); + result = prime * result + (includeTwitterClientHeader ? 1231 : 1237); + result = prime * result + maxTotalConnections; + result = prime * result + (oAuthAccessToken == null ? 0 : oAuthAccessToken.hashCode()); + result = prime * result + (oAuthAccessTokenSecret == null ? 0 : oAuthAccessTokenSecret.hashCode()); + result = prime * result + (oAuthAccessTokenURL == null ? 0 : oAuthAccessTokenURL.hashCode()); + result = prime * result + (oAuthAuthenticationURL == null ? 0 : oAuthAuthenticationURL.hashCode()); + result = prime * result + (oAuthAuthorizationURL == null ? 0 : oAuthAuthorizationURL.hashCode()); + result = prime * result + (oAuthBaseURL == null ? 0 : oAuthBaseURL.hashCode()); + result = prime * result + (oAuthConsumerKey == null ? 0 : oAuthConsumerKey.hashCode()); + result = prime * result + (oAuthConsumerSecret == null ? 0 : oAuthConsumerSecret.hashCode()); + result = prime * result + (oAuthRequestTokenURL == null ? 0 : oAuthRequestTokenURL.hashCode()); + result = prime * result + (password == null ? 0 : password.hashCode()); + result = prime * result + (prettyDebug ? 1231 : 1237); + result = prime * result + (requestHeaders == null ? 0 : requestHeaders.hashCode()); + result = prime * result + (restBaseURL == null ? 0 : restBaseURL.hashCode()); + result = prime * result + (signingOAuthAccessTokenURL == null ? 0 : signingOAuthAccessTokenURL.hashCode()); + result = prime * result + + (signingOAuthAuthenticationURL == null ? 0 : signingOAuthAuthenticationURL.hashCode()); + result = prime * result + (signingOAuthAuthorizationURL == null ? 0 : signingOAuthAuthorizationURL.hashCode()); + result = prime * result + (signingOAuthBaseURL == null ? 0 : signingOAuthBaseURL.hashCode()); + result = prime * result + (signingOAuthRequestTokenURL == null ? 0 : signingOAuthRequestTokenURL.hashCode()); + result = prime * result + (signingRestBaseURL == null ? 0 : signingRestBaseURL.hashCode()); + result = prime * result + (useSSL ? 1231 : 1237); + result = prime * result + (user == null ? 0 : user.hashCode()); + result = prime * result + (userAgent == null ? 0 : userAgent.hashCode()); + return result; + } + + @Override + public final boolean isDebugEnabled() { + return debug; + } + + @Override + public boolean isIncludeCardsEnabled() { + return includeCards; + } + + @Override + public boolean isGZIPEnabled() { + return gzipEnabled; + } + + @Override + public boolean isIncludeEntitiesEnabled() { + return includeEntitiesEnabled; + } + + @Override + public boolean isIncludeRTsEnabled() { + return includeRTsEnabled; + } + + @Override + public boolean isIncludeReplyCountEnabled() { + return includeReplyCountEnabled; + } + + @Override + public boolean isIncludeDescendentReplyCountEnabled() { + return includeDescendentReplyCountEnabled; + } + + @Override + public boolean isPrettyDebugEnabled() { + return prettyDebug; + } + + @Override + public boolean isProxyConfigured() { + return (getHttpProxyHost() != null || "".equals(getHttpProxyHost())) && getHttpProxyPort() > 0; + } + + @Override + public boolean isSSLEnabled() { + return getRestBaseURL() != null && getRestBaseURL().startsWith("https://"); + } + + @Override + public final boolean isSSLErrorIgnored() { + return ignoreSSLError; + } + + @Override + public boolean isTwitterClientHeaderIncluded() { + return includeTwitterClientHeader; + } + + public void setCardsPlatform(String cardsPlatform) { + this.cardsPlatform = cardsPlatform; + } + + public void setIncludeCards(boolean includeCards) { + this.includeCards = includeCards; + } + + @Override + public String toString() { + return "ConfigurationBase{debug=" + debug + ", userAgent=" + userAgent + ", user=" + user + ", password=" + + password + ", useSSL=" + useSSL + ", ignoreSSLError=" + ignoreSSLError + ", prettyDebug=" + + prettyDebug + ", gzipEnabled=" + gzipEnabled + ", httpProxyHost=" + httpProxyHost + + ", httpProxyUser=" + httpProxyUser + ", httpProxyPassword=" + httpProxyPassword + ", httpProxyPort=" + + httpProxyPort + ", httpConnectionTimeout=" + httpConnectionTimeout + ", httpReadTimeout=" + + httpReadTimeout + ", httpRetryCount=" + httpRetryCount + ", httpRetryIntervalSeconds=" + + httpRetryIntervalSeconds + ", maxTotalConnections=" + maxTotalConnections + ", defaultMaxPerRoute=" + + defaultMaxPerRoute + ", oAuthConsumerKey=" + oAuthConsumerKey + ", oAuthConsumerSecret=" + + oAuthConsumerSecret + ", oAuthAccessToken=" + oAuthAccessToken + ", oAuthAccessTokenSecret=" + + oAuthAccessTokenSecret + ", oAuthRequestTokenURL=" + oAuthRequestTokenURL + + ", oAuthAuthorizationURL=" + oAuthAuthorizationURL + ", oAuthAccessTokenURL=" + oAuthAccessTokenURL + + ", oAuthAuthenticationURL=" + oAuthAuthenticationURL + ", signingOAuthRequestTokenURL=" + + signingOAuthRequestTokenURL + ", signingOAuthAuthorizationURL=" + signingOAuthAuthorizationURL + + ", signingOAuthAccessTokenURL=" + signingOAuthAccessTokenURL + ", signingOAuthAuthenticationURL=" + + signingOAuthAuthenticationURL + ", oAuthBaseURL=" + oAuthBaseURL + ", signingOAuthBaseURL=" + + signingOAuthBaseURL + ", signingRestBaseURL=" + signingRestBaseURL + ", restBaseURL=" + restBaseURL + + ", includeRTsEnabled=" + includeRTsEnabled + ", includeEntitiesEnabled=" + includeEntitiesEnabled + + ", includeTwitterClientHeader=" + includeTwitterClientHeader + ", clientVersion=" + clientVersion + + ", clientURL=" + clientURL + ", clientName=" + clientName + ", httpClientFactory=" + + httpClientFactory + ", hostAddressResolverFactory=" + hostAddressResolverFactory + + ", requestHeaders=" + requestHeaders + "}"; + } + + protected void cacheInstance() { + cacheInstance(this); + } + + // assures equality after deserializedation + protected Object readResolve() throws ObjectStreamException { + return getInstance(this); + } + + protected final void setClientName(final String clientName) { + this.clientName = clientName; + initRequestHeaders(); + } + + protected final void setClientURL(final String clientURL) { + this.clientURL = clientURL; + initRequestHeaders(); + } + + protected final void setClientVersion(final String clientVersion) { + this.clientVersion = clientVersion; + initRequestHeaders(); + } + + protected final void setDebug(final boolean debug) { + this.debug = debug; + } + + protected final void setGZIPEnabled(final boolean gzipEnabled) { + this.gzipEnabled = gzipEnabled; + initRequestHeaders(); + } + + protected void setHostAddressResolverFactory(final HostAddressResolverFactory factory) { + hostAddressResolverFactory = factory; + } + + protected void setHttpClientFactory(final HttpClientFactory factory) { + httpClientFactory = factory; + } + + protected final void setHttpConnectionTimeout(final int connectionTimeout) { + httpConnectionTimeout = connectionTimeout; + } + + protected final void setHttpDefaultMaxPerRoute(final int defaultMaxPerRoute) { + this.defaultMaxPerRoute = defaultMaxPerRoute; + } + + protected final void setHttpMaxTotalConnections(final int maxTotalConnections) { + this.maxTotalConnections = maxTotalConnections; + } + + protected final void setHttpProxyHost(final String proxyHost) { + httpProxyHost = proxyHost; + initRequestHeaders(); + } + + protected final void setHttpProxyPassword(final String proxyPassword) { + httpProxyPassword = proxyPassword; + } + + protected final void setHttpProxyPort(final int proxyPort) { + httpProxyPort = proxyPort; + initRequestHeaders(); + } + + protected final void setHttpProxyUser(final String proxyUser) { + httpProxyUser = proxyUser; + } + + protected final void setHttpReadTimeout(final int readTimeout) { + httpReadTimeout = readTimeout; + } + + protected final void setHttpRetryCount(final int retryCount) { + httpRetryCount = retryCount; + } + + protected final void setHttpRetryIntervalSeconds(final int retryIntervalSeconds) { + httpRetryIntervalSeconds = retryIntervalSeconds; + } + + protected final void setHttpUserAgent(final String userAgent) { + this.userAgent = userAgent; + initRequestHeaders(); + } + + protected final void setIgnoreSSLError(final boolean ignore) { + ignoreSSLError = ignore; + initRequestHeaders(); + } + + protected final void setIncludeEntitiesEnabled(final boolean enabled) { + includeEntitiesEnabled = enabled; + } + + protected final void setIncludeRTsEnabled(final boolean enabled) { + includeRTsEnabled = enabled; + } + + protected final void setIncludeReplyCountEnabled(final boolean enabled) { + includeReplyCountEnabled = enabled; + } + + protected final void setIncludeDescendentReplyCountEnabled(final boolean enabled) { + includeDescendentReplyCountEnabled = enabled; + } + + protected final void setIncludeTwitterClientHeader(final boolean includeHeader) { + includeTwitterClientHeader = includeHeader; + initRequestHeaders(); + } + + protected final void setOAuthAccessToken(final String accessToken) { + oAuthAccessToken = accessToken; + } + + protected final void setOAuthAccessTokenSecret(final String accessTokenSecret) { + oAuthAccessTokenSecret = accessTokenSecret; + } + + public void setOAuthAuthorizationURL(String oAuthAuthorizationURL) { +// this.oAuthAuthorizationURL = oAuthAuthorizationURL; + } + + protected final void setOAuthBaseURL(String oAuthBaseURL) { + if (isNullOrEmpty(oAuthBaseURL)) { + oAuthBaseURL = DEFAULT_OAUTH_BASE_URL; + } + this.oAuthBaseURL = fixURLSlash(oAuthBaseURL); + + oAuthAccessTokenURL = oAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN; + oAuthAuthenticationURL = oAuthBaseURL + PATH_SEGMENT_AUTHENTICATION; + oAuthAuthorizationURL = oAuthBaseURL + PATH_SEGMENT_AUTHORIZATION; + oAuthRequestTokenURL = oAuthBaseURL + PATH_SEGMENT_REQUEST_TOKEN; + + setSigningOAuthBaseURL(oAuthBaseURL); + fixOAuthBaseURL(); + } + + protected final void setOAuthConsumerKey(final String oAuthConsumerKey) { + this.oAuthConsumerKey = oAuthConsumerKey; + fixRestBaseURL(); + } + + protected final void setOAuthConsumerSecret(final String oAuthConsumerSecret) { + this.oAuthConsumerSecret = oAuthConsumerSecret; + fixRestBaseURL(); + } + + protected final void setPassword(final String password) { + this.password = password; + } + + protected final void setPrettyDebugEnabled(final boolean prettyDebug) { + this.prettyDebug = prettyDebug; + } + + protected final void setRestBaseURL(String restBaseURL) { + if (isNullOrEmpty(restBaseURL)) { + restBaseURL = DEFAULT_REST_BASE_URL; + } + this.restBaseURL = fixURLSlash(restBaseURL); + fixRestBaseURL(); + } + + protected final void setSigningOAuthBaseURL(String signingOAuthBaseURL) { + if (isNullOrEmpty(signingOAuthBaseURL)) { + signingOAuthBaseURL = DEFAULT_SIGNING_OAUTH_BASE_URL; + } + this.signingOAuthBaseURL = fixURLSlash(signingOAuthBaseURL); + + signingOAuthAccessTokenURL = signingOAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN; + signingOAuthAuthenticationURL = signingOAuthBaseURL + PATH_SEGMENT_AUTHENTICATION; + signingOAuthAuthorizationURL = signingOAuthBaseURL + PATH_SEGMENT_AUTHORIZATION; + signingOAuthRequestTokenURL = signingOAuthBaseURL + PATH_SEGMENT_REQUEST_TOKEN; + + fixOAuthBaseURL(); + } + + protected final void setSigningRestBaseURL(String signingRestBaseURL) { + if (isNullOrEmpty(signingRestBaseURL)) { + signingRestBaseURL = DEFAULT_SIGNING_REST_BASE_URL; + } + this.signingRestBaseURL = fixURLSlash(signingRestBaseURL); + fixRestBaseURL(); + } + + protected void setSigningUploadBaseURL(String signingUploadBaseURL) { + if (isNullOrEmpty(signingUploadBaseURL)) { + signingUploadBaseURL = DEFAULT_SIGNING_UPLOAD_BASE_URL; + } + this.signingUploadBaseURL = fixURLSlash(signingUploadBaseURL); + fixUploadBaseURL(); + } + + protected void setUploadBaseURL(String uploadBaseURL) { + if (isNullOrEmpty(uploadBaseURL)) { + uploadBaseURL = DEFAULT_UPLOAD_BASE_URL; + } + this.uploadBaseURL = fixURLSlash(uploadBaseURL); + fixUploadBaseURL(); + } + + protected final void setUser(final String user) { + this.user = user; + } + + protected final void setUseSSL(final boolean useSSL) { + this.useSSL = useSSL; + fixRestBaseURL(); + } + + private void fixOAuthBaseURL() { + if (DEFAULT_OAUTH_BASE_URL.equals(fixURL(DEFAULT_USE_SSL, oAuthBaseURL))) { + oAuthBaseURL = fixURL(useSSL, oAuthBaseURL); + } + if (oAuthBaseURL != null && oAuthBaseURL.equals(fixURL(DEFAULT_USE_SSL, signingOAuthBaseURL))) { + signingOAuthBaseURL = fixURL(useSSL, signingOAuthBaseURL); + } + if (oAuthBaseURL != null + && (oAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN).equals(fixURL(DEFAULT_USE_SSL, oAuthAccessTokenURL))) { + oAuthAccessTokenURL = fixURL(useSSL, oAuthAccessTokenURL); + } + if (oAuthBaseURL != null + && (oAuthBaseURL + PATH_SEGMENT_AUTHENTICATION).equals(fixURL(DEFAULT_USE_SSL, oAuthAuthenticationURL))) { + oAuthAuthenticationURL = fixURL(useSSL, oAuthAuthenticationURL); + } + if (oAuthBaseURL != null + && (oAuthBaseURL + PATH_SEGMENT_AUTHORIZATION).equals(fixURL(DEFAULT_USE_SSL, oAuthAuthorizationURL))) { + oAuthAuthorizationURL = fixURL(useSSL, oAuthAuthorizationURL); + } + if (oAuthBaseURL != null + && (oAuthBaseURL + PATH_SEGMENT_REQUEST_TOKEN).equals(fixURL(DEFAULT_USE_SSL, oAuthRequestTokenURL))) { + oAuthRequestTokenURL = fixURL(useSSL, oAuthRequestTokenURL); + } + if (signingOAuthBaseURL != null + && (signingOAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN).equals(fixURL(DEFAULT_USE_SSL, + signingOAuthAccessTokenURL))) { + signingOAuthAccessTokenURL = fixURL(useSSL, signingOAuthAccessTokenURL); + } + if (signingOAuthBaseURL != null + && (signingOAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN).equals(fixURL(DEFAULT_USE_SSL, + signingOAuthAuthenticationURL))) { + signingOAuthAuthenticationURL = fixURL(useSSL, signingOAuthAuthenticationURL); + } + if (signingOAuthBaseURL != null + && (signingOAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN).equals(fixURL(DEFAULT_USE_SSL, + signingOAuthAuthorizationURL))) { + signingOAuthAuthorizationURL = fixURL(useSSL, signingOAuthAuthorizationURL); + } + if (signingOAuthBaseURL != null + && (signingOAuthBaseURL + PATH_SEGMENT_ACCESS_TOKEN).equals(fixURL(DEFAULT_USE_SSL, + signingOAuthRequestTokenURL))) { + signingOAuthRequestTokenURL = fixURL(useSSL, signingOAuthRequestTokenURL); + } + initRequestHeaders(); + } + + private void fixRestBaseURL() { + if (DEFAULT_REST_BASE_URL.equals(fixURL(DEFAULT_USE_SSL, restBaseURL))) { + restBaseURL = fixURL(useSSL, restBaseURL); + } + if (restBaseURL != null && restBaseURL.equals(fixURL(DEFAULT_USE_SSL, signingRestBaseURL))) { + signingRestBaseURL = fixURL(useSSL, signingRestBaseURL); + } + initRequestHeaders(); + } + + private void fixUploadBaseURL() { + if (DEFAULT_UPLOAD_BASE_URL.equals(fixURL(DEFAULT_USE_SSL, uploadBaseURL))) { + uploadBaseURL = fixURL(useSSL, uploadBaseURL); + } + if (uploadBaseURL != null && uploadBaseURL.equals(fixURL(DEFAULT_USE_SSL, uploadBaseURL))) { + uploadBaseURL = fixURL(useSSL, uploadBaseURL); + } + initRequestHeaders(); + } + + final void initRequestHeaders() { + requestHeaders = new HeaderMap(); + if (includeTwitterClientHeader) { + requestHeaders.addHeader("X-Twitter-Client-Version", getClientVersion()); + requestHeaders.addHeader("X-Twitter-Client-URL", getClientURL()); + requestHeaders.addHeader("X-Twitter-Client", getClientName()); + } + + requestHeaders.addHeader("User-Agent", getHttpUserAgent()); + if (gzipEnabled) { + requestHeaders.addHeader("Accept-Encoding", "gzip"); + } + // I found this may cause "Socket is closed" error in Android, so I + // changed it to "keep-alive". + if (!isNullOrEmpty(httpProxyHost) && httpProxyPort > 0) { + requestHeaders.addHeader("Connection", "keep-alive"); + } else { + requestHeaders.addHeader("Connection", "close"); + } + } + + private static void cacheInstance(final ConfigurationBase conf) { + if (!instances.contains(conf)) { + instances.add(conf); + } + } + + private static ConfigurationBase getInstance(final ConfigurationBase configurationBase) { + int index; + if ((index = instances.indexOf(configurationBase)) == -1) { + instances.add(configurationBase); + return configurationBase; + } else + return instances.get(index); + } + + static String fixURL(final boolean useSSL, String url) { + if (null == url) return null; + if (!url.startsWith("http://") || !url.startsWith("https://")) { + url = "https://" + url; + } + final int index = url.indexOf("://"); + if (-1 == index) throw new IllegalArgumentException("url should contain '://'"); + final String hostAndLater = url.substring(index + 3); + if (useSSL) + return "https://" + hostAndLater; + else + return "http://" + hostAndLater; + } + + static String fixURLSlash(final String urlOrig) { + if (urlOrig == null) return null; + if (!urlOrig.endsWith("/")) return urlOrig + "/"; + return urlOrig; + } + + static boolean isNullOrEmpty(final String string) { + if (string == null) return true; + if (string.length() == 0) return true; + return false; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationBuilder.java b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationBuilder.java new file mode 100644 index 00000000..ad0a22c1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationBuilder.java @@ -0,0 +1,346 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +import twitter4j.http.HostAddressResolverFactory; +import twitter4j.http.HttpClientFactory; + +/** + * A builder that can be used to construct a twitter4j configuration with + * desired settings. This builder has sensible defaults such that + * {@code new ConfigurationBuilder().build()} would create a usable + * configuration. This configuration builder is useful for clients that wish to + * configure twitter4j in unit tests or from command line flags for example. + * + * @author John Sirois - john.sirois at gmail.com + */ +public final class ConfigurationBuilder { + + private ConfigurationBase configuration = new ConfigurationBase(); + + public ConfigurationBuilder() { + + } + + public ConfigurationBuilder(final Configuration conf) { + configuration.setClientName(conf.getClientName()); + configuration.setClientURL(conf.getClientURL()); + configuration.setClientVersion(conf.getClientVersion()); + configuration.setDebug(conf.isDebugEnabled()); + configuration.setGZIPEnabled(conf.isGZIPEnabled()); + configuration.setHostAddressResolverFactory(conf.getHostAddressResolverFactory()); + configuration.setHttpClientFactory(conf.getHttpClientFactory()); + configuration.setHttpConnectionTimeout(conf.getHttpConnectionTimeout()); + configuration.setHttpDefaultMaxPerRoute(conf.getHttpDefaultMaxPerRoute()); + configuration.setHttpMaxTotalConnections(conf.getHttpMaxTotalConnections()); + configuration.setHttpProxyHost(conf.getHttpProxyHost()); + configuration.setHttpProxyPassword(conf.getHttpProxyPassword()); + configuration.setHttpProxyPort(conf.getHttpProxyPort()); + configuration.setHttpProxyUser(conf.getHttpProxyUser()); + configuration.setHttpReadTimeout(conf.getHttpReadTimeout()); + configuration.setHttpRetryCount(conf.getHttpRetryCount()); + configuration.setHttpRetryIntervalSeconds(conf.getHttpRetryIntervalSeconds()); + configuration.setHttpUserAgent(conf.getHttpUserAgent()); + configuration.setIgnoreSSLError(conf.isSSLErrorIgnored()); + configuration.setIncludeEntitiesEnabled(conf.isIncludeEntitiesEnabled()); + configuration.setIncludeRTsEnabled(conf.isIncludeRTsEnabled()); + configuration.setIncludeReplyCountEnabled(conf.isIncludeReplyCountEnabled()); + configuration.setIncludeDescendentReplyCountEnabled(conf.isIncludeDescendentReplyCountEnabled()); + configuration.setIncludeRTsEnabled(conf.isIncludeRTsEnabled()); + configuration.setIncludeTwitterClientHeader(conf.isTwitterClientHeaderIncluded()); + configuration.setOAuthAccessToken(conf.getOAuthAccessToken()); + configuration.setOAuthAccessTokenSecret(conf.getOAuthAccessTokenSecret()); + configuration.setOAuthBaseURL(conf.getOAuthBaseURL()); + configuration.setOAuthConsumerKey(conf.getOAuthConsumerKey()); + configuration.setOAuthConsumerSecret(conf.getOAuthConsumerSecret()); + configuration.setPassword(conf.getPassword()); + configuration.setPrettyDebugEnabled(conf.isPrettyDebugEnabled()); + configuration.setRestBaseURL(conf.getRestBaseURL()); + configuration.setSigningOAuthBaseURL(conf.getSigningOAuthBaseURL()); + configuration.setSigningRestBaseURL(conf.getSigningRestBaseURL()); + configuration.setUploadBaseURL(conf.getUploadBaseURL()); + configuration.setSigningUploadBaseURL(conf.getSigningUploadBaseURL()); + configuration.setUser(conf.getUser()); + configuration.setUseSSL(conf.isSSLEnabled()); + configuration.setIncludeCards(conf.isIncludeCardsEnabled()); + configuration.setCardsPlatform(conf.getCardsPlatform()); + } + + public Configuration build() { + checkNotBuilt(); + configuration.cacheInstance(); + try { + return configuration; + } finally { + configuration = null; + } + } + + public ConfigurationBuilder setClientName(final String clientName) { + checkNotBuilt(); + configuration.setClientName(clientName); + return this; + } + + public ConfigurationBuilder setClientURL(final String clientURL) { + checkNotBuilt(); + configuration.setClientURL(clientURL); + return this; + } + + public ConfigurationBuilder setClientVersion(final String clientVersion) { + checkNotBuilt(); + configuration.setClientVersion(clientVersion); + return this; + } + + public ConfigurationBuilder setDebugEnabled(final boolean debugEnabled) { + checkNotBuilt(); + configuration.setDebug(debugEnabled); + return this; + } + + public ConfigurationBuilder setGZIPEnabled(final boolean gzipEnabled) { + checkNotBuilt(); + configuration.setGZIPEnabled(gzipEnabled); + return this; + } + + public ConfigurationBuilder setHostAddressResolverFactory(final HostAddressResolverFactory factory) { + checkNotBuilt(); + configuration.setHostAddressResolverFactory(factory); + return this; + } + + public ConfigurationBuilder setHttpClientFactory(final HttpClientFactory factory) { + checkNotBuilt(); + configuration.setHttpClientFactory(factory); + return this; + } + + public ConfigurationBuilder setHttpConnectionTimeout(final int httpConnectionTimeout) { + checkNotBuilt(); + configuration.setHttpConnectionTimeout(httpConnectionTimeout); + return this; + } + + public ConfigurationBuilder setHttpDefaultMaxPerRoute(final int httpDefaultMaxPerRoute) { + checkNotBuilt(); + configuration.setHttpDefaultMaxPerRoute(httpDefaultMaxPerRoute); + return this; + } + + public ConfigurationBuilder setHttpMaxTotalConnections(final int httpMaxConnections) { + checkNotBuilt(); + configuration.setHttpMaxTotalConnections(httpMaxConnections); + return this; + } + + public ConfigurationBuilder setHttpProxyHost(final String httpProxyHost) { + checkNotBuilt(); + configuration.setHttpProxyHost(httpProxyHost); + return this; + } + + public ConfigurationBuilder setHttpProxyPassword(final String httpProxyPassword) { + checkNotBuilt(); + configuration.setHttpProxyPassword(httpProxyPassword); + return this; + } + + public ConfigurationBuilder setHttpProxyPort(final int httpProxyPort) { + checkNotBuilt(); + configuration.setHttpProxyPort(httpProxyPort); + return this; + } + + public ConfigurationBuilder setHttpProxyUser(final String httpProxyUser) { + checkNotBuilt(); + configuration.setHttpProxyUser(httpProxyUser); + return this; + } + + public ConfigurationBuilder setHttpReadTimeout(final int httpReadTimeout) { + checkNotBuilt(); + configuration.setHttpReadTimeout(httpReadTimeout); + return this; + } + + public ConfigurationBuilder setHttpRetryCount(final int httpRetryCount) { + checkNotBuilt(); + configuration.setHttpRetryCount(httpRetryCount); + return this; + } + + public ConfigurationBuilder setHttpRetryIntervalSeconds(final int httpRetryIntervalSeconds) { + checkNotBuilt(); + configuration.setHttpRetryIntervalSeconds(httpRetryIntervalSeconds); + return this; + } + + public ConfigurationBuilder setHttpUserAgent(final String userAgent) { + checkNotBuilt(); + configuration.setHttpUserAgent(userAgent); + return this; + } + + public ConfigurationBuilder setIgnoreSSLError(final boolean ignoreSSLError) { + checkNotBuilt(); + configuration.setIgnoreSSLError(ignoreSSLError); + return this; + } + + public ConfigurationBuilder setIncludeEntitiesEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setIncludeEntitiesEnabled(enabled); + return this; + } + + public ConfigurationBuilder setIncludeRTsEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setIncludeRTsEnabled(enabled); + return this; + } + + + public ConfigurationBuilder setIncludeReplyCountEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setIncludeReplyCountEnabled(enabled); + return this; + } + + public ConfigurationBuilder setIncludeDescendentReplyCountEnabled(final boolean enabled) { + checkNotBuilt(); + configuration.setIncludeDescendentReplyCountEnabled(enabled); + return this; + } + + public ConfigurationBuilder setIncludeTwitterClientHeader(final boolean includeTwitterClientHeader) { + checkNotBuilt(); + configuration.setIncludeTwitterClientHeader(includeTwitterClientHeader); + return this; + } + + public ConfigurationBuilder setOAuthAccessToken(final String oAuthAccessToken) { + checkNotBuilt(); + configuration.setOAuthAccessToken(oAuthAccessToken); + return this; + } + + public ConfigurationBuilder setOAuthAccessTokenSecret(final String oAuthAccessTokenSecret) { + checkNotBuilt(); + configuration.setOAuthAccessTokenSecret(oAuthAccessTokenSecret); + return this; + } + + public ConfigurationBuilder setOAuthBaseURL(final String oAuthBaseURL) { + checkNotBuilt(); + configuration.setOAuthBaseURL(oAuthBaseURL); + return this; + } + + + public ConfigurationBuilder setOAuthAuthorizationURL(final String oAuthAuthorizationURL) { + checkNotBuilt(); + configuration.setOAuthAuthorizationURL(oAuthAuthorizationURL); + return this; + } + + public ConfigurationBuilder setOAuthConsumerKey(final String oAuthConsumerKey) { + checkNotBuilt(); + configuration.setOAuthConsumerKey(oAuthConsumerKey); + return this; + } + + public ConfigurationBuilder setOAuthConsumerSecret(final String oAuthConsumerSecret) { + checkNotBuilt(); + configuration.setOAuthConsumerSecret(oAuthConsumerSecret); + return this; + } + + public ConfigurationBuilder setPassword(final String password) { + checkNotBuilt(); + configuration.setPassword(password); + return this; + } + + public ConfigurationBuilder setPrettyDebugEnabled(final boolean prettyDebugEnabled) { + checkNotBuilt(); + configuration.setPrettyDebugEnabled(prettyDebugEnabled); + return this; + } + + public ConfigurationBuilder setRestBaseURL(final String restBaseURL) { + checkNotBuilt(); + configuration.setRestBaseURL(restBaseURL); + return this; + } + + public ConfigurationBuilder setSigningOAuthBaseURL(final String signingOAuthBaseURL) { + checkNotBuilt(); + configuration.setSigningOAuthBaseURL(signingOAuthBaseURL); + return this; + } + + public ConfigurationBuilder setSigningRestBaseURL(final String signingRestBaseURL) { + checkNotBuilt(); + configuration.setSigningRestBaseURL(signingRestBaseURL); + return this; + } + + public ConfigurationBuilder setSigningUploadBaseURL(final String signingUploadBaseURL) { + checkNotBuilt(); + configuration.setSigningUploadBaseURL(signingUploadBaseURL); + return this; + } + + public ConfigurationBuilder setUploadBaseURL(final String uploadBaseURL) { + checkNotBuilt(); + configuration.setUploadBaseURL(uploadBaseURL); + return this; + } + + public ConfigurationBuilder setUser(final String user) { + checkNotBuilt(); + configuration.setUser(user); + return this; + } + + public ConfigurationBuilder setUseSSL(final boolean useSSL) { + checkNotBuilt(); + configuration.setUseSSL(useSSL); + return this; + } + + public ConfigurationBuilder setIncludeCards(final boolean includeCards) { + checkNotBuilt(); + configuration.setIncludeCards(includeCards); + return this; + } + + + public ConfigurationBuilder setCardsPlatform(final String cardsPlatform) { + checkNotBuilt(); + configuration.setCardsPlatform(cardsPlatform); + return this; + } + + private void checkNotBuilt() { + if (configuration == null) + throw new IllegalStateException("Cannot use this builder any longer, build() has already been called"); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationContext.java b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationContext.java new file mode 100644 index 00000000..59d9b1af --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationContext.java @@ -0,0 +1,32 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +/** + * Static factory of Configuration. This class wraps ConfigurationFactory + * implementations.
+ * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class ConfigurationContext { + private static final ConfigurationFactory factory = new BaseConfigurationFactory(); + + public static Configuration getInstance() { + return factory.getInstance(); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationFactory.java new file mode 100644 index 00000000..e0beed6d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/conf/ConfigurationFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.conf; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface ConfigurationFactory { + /** + * clean up resources acquired by this factory. + */ + void dispose(); + + /** + * returns the root configuration + * + * @return root configuration + */ + Configuration getInstance(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/BASE64Encoder.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/BASE64Encoder.java new file mode 100644 index 00000000..4fa72d6b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/BASE64Encoder.java @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +/** + * A utility class encodes byte array into String using Base64 encoding scheme. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see HttpClient + */ +public final class BASE64Encoder { + private static final char last2byte = (char) Integer.parseInt("00000011", 2); + private static final char last4byte = (char) Integer.parseInt("00001111", 2); + private static final char last6byte = (char) Integer.parseInt("00111111", 2); + private static final char lead6byte = (char) Integer.parseInt("11111100", 2); + private static final char lead4byte = (char) Integer.parseInt("11110000", 2); + private static final char lead2byte = (char) Integer.parseInt("11000000", 2); + private static final char[] encodeTable = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; + + private BASE64Encoder() { + } + + public static String encode(final byte[] from) { + final StringBuffer to = new StringBuffer((int) (from.length * 1.34) + 3); + int num = 0; + char currentByte = 0; + for (int i = 0; i < from.length; i++) { + num = num % 8; + while (num < 8) { + switch (num) { + case 0: + currentByte = (char) (from[i] & lead6byte); + currentByte = (char) (currentByte >>> 2); + break; + case 2: + currentByte = (char) (from[i] & last6byte); + break; + case 4: + currentByte = (char) (from[i] & last4byte); + currentByte = (char) (currentByte << 2); + if (i + 1 < from.length) { + currentByte |= (from[i + 1] & lead2byte) >>> 6; + } + break; + case 6: + currentByte = (char) (from[i] & last2byte); + currentByte = (char) (currentByte << 4); + if (i + 1 < from.length) { + currentByte |= (from[i + 1] & lead4byte) >>> 4; + } + break; + } + to.append(encodeTable[currentByte]); + num += 6; + } + } + if (to.length() % 4 != 0) { + for (int i = 4 - to.length() % 4; i > 0; i--) { + to.append("="); + } + } + return to.toString(); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/FactoryUtils.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/FactoryUtils.java new file mode 100644 index 00000000..3e7eb1c4 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/FactoryUtils.java @@ -0,0 +1,17 @@ +package twitter4j.http; + +public class FactoryUtils { + public static HostAddressResolver getHostAddressResolver(final HttpClientConfiguration conf) { + final HostAddressResolverFactory factory = conf.getHostAddressResolverFactory(); + if (factory == null) return null; + return factory.getInstance(conf); + } + + public static HttpClient getHttpClient(final HttpClientConfiguration conf) { + final HttpClientFactory factory = conf.getHttpClientFactory(); + if (factory == null) return new HttpClientImpl(conf); + final HttpClient client = factory.getInstance(conf); + if (client == null) return new HttpClientImpl(conf); + return client; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HTMLEntity.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HTMLEntity.java new file mode 100644 index 00000000..e50066a3 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HTMLEntity.java @@ -0,0 +1,905 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +import java.util.HashMap; +import java.util.Map; + +public final class HTMLEntity { + private static Map entityEscapeMap = new HashMap(); + + private static Map escapeEntityMap = new HashMap(); + + static { + final String[][] entities = { { " ", " "/* + * no-break space = + * non-breaking space + */, "\u00A0" }, { "¡", "¡"/* + * inverted + * exclamation + * mark + */, "\u00A1" }, + { "¢", "¢"/* cent sign */, "\u00A2" }, { "£", "£"/* + * pound + * sign + */, "\u00A3" }, + { "¤", "¤"/* currency sign */, "\u00A4" }, { "¥", "¥"/* + * yen + * sign + * = + * yuan + * sign + */, "\u00A5" }, + { "¦", "¦"/* broken bar = broken vertical bar */, "\u00A6" }, + { "§", "§"/* section sign */, "\u00A7" }, { "¨", "¨"/* + * diaeresis + * = + * spacing + * diaeresis + */, "\u00A8" }, + { "©", "©"/* copyright sign */, "\u00A9" }, { "ª", "ª"/* + * feminine + * ordinal + * indicator + */, "\u00AA" }, + { "«", "«"/* + * left-pointing double angle quotation mark + * = left pointing guillemet + */, "\u00AB" }, { "¬", "¬"/* + * not + * sign + * = + * discretionary + * hyphen + */, "\u00AC" }, + { "­", "­"/* soft hyphen = discretionary hyphen */, "\u00AD" }, + { "®", "®"/* + * registered sign = registered trade mark + * sign + */, "\u00AE" }, { "¯", "¯"/* + * macron + * = + * spacing + * macron + * = + * overline + * = APL + * overbar + */, "\u00AF" }, + { "°", "°"/* degree sign */, "\u00B0" }, { "±", "±"/* + * plus + * - + * minus + * sign + * = + * plus + * - + * or + * - + * minus + * sign + */, "\u00B1" }, + { "²", "²"/* + * superscript two = superscript digit two = + * squared + */, "\u00B2" }, { "³", "³"/* + * superscript + * three + * = + * superscript + * digit + * three + * = + * cubed + */, "\u00B3" }, + { "´", "´"/* acute accent = spacing acute */, "\u00B4" }, + { "µ", "µ"/* micro sign */, "\u00B5" }, { "¶", "¶"/* + * pilcrow + * sign + * = + * paragraph + * sign + */, "\u00B6" }, + { "·", "·"/* + * middle dot = Georgian comma = Greek + * middle dot + */, "\u00B7" }, { "¸", "¸"/* + * cedilla + * = + * spacing + * cedilla + */, "\u00B8" }, + { "¹", "¹"/* + * superscript one = superscript digit one + */, "\u00B9" }, { "º", "º"/* + * masculine + * ordinal + * indicator + */, "\u00BA" }, + { "»", "»"/* + * right-pointing double angle quotation + * mark = right pointing guillemet + */, "\u00BB" }, { "¼", "¼"/* + * vulgar + * fraction + * one + * quarter + * = + * fraction + * one + * quarter + */, "\u00BC" }, + { "½", "½"/* + * vulgar fraction one half = fraction one + * half + */, "\u00BD" }, { "¾", "¾"/* + * vulgar + * fraction + * three + * quarters + * = + * fraction + * three + * quarters + */, "\u00BE" }, + { "¿", "¿"/* + * inverted question mark = turned question + * mark + */, "\u00BF" }, { "À", "À"/* + * latin + * capital + * letter + * A + * with + * grave + * = + * latin + * capital + * letter + * A + * grave + */, "\u00C0" }, + { "Á", "Á"/* latin capital letter A with acute */, "\u00C1" }, + { "Â", "Â"/* + * latin capital letter A with circumflex + */, "\u00C2" }, { "Ã", "Ã"/* + * latin + * capital + * letter + * A + * with + * tilde + */, "\u00C3" }, + { "Ä", "Ä"/* + * latin capital letter A with diaeresis + */, "\u00C4" }, { "Å", "Å"/* + * latin + * capital + * letter + * A + * with + * ring + * above + * = + * latin + * capital + * letter + * A + * ring + */, "\u00C5" }, + { "Æ", "Æ"/* + * latin capital letter AE = latin capital + * ligature AE + */, "\u00C6" }, { "Ç", "Ç"/* + * latin + * capital + * letter + * C + * with + * cedilla + */, "\u00C7" }, + { "È", "È"/* latin capital letter E with grave */, "\u00C8" }, + { "É", "É"/* latin capital letter E with acute */, "\u00C9" }, + { "Ê", "Ê"/* + * latin capital letter E with circumflex + */, "\u00CA" }, { "Ë", "Ë"/* + * latin + * capital + * letter + * E + * with + * diaeresis + */, "\u00CB" }, + { "Ì", "Ì"/* latin capital letter I with grave */, "\u00CC" }, + { "Í", "Í"/* latin capital letter I with acute */, "\u00CD" }, + { "Î", "Î"/* + * latin capital letter I with circumflex + */, "\u00CE" }, { "Ï", "Ï"/* + * latin + * capital + * letter + * I + * with + * diaeresis + */, "\u00CF" }, + { "Ð", "Ð"/* latin capital letter ETH */, "\u00D0" }, { "Ñ", "Ñ"/* + * latin + * capital + * letter + * N + * with + * tilde + */, "\u00D1" }, + { "Ò", "Ò"/* latin capital letter O with grave */, "\u00D2" }, + { "Ó", "Ó"/* latin capital letter O with acute */, "\u00D3" }, + { "Ô", "Ô"/* + * latin capital letter O with circumflex + */, "\u00D4" }, { "Õ", "Õ"/* + * latin + * capital + * letter + * O + * with + * tilde + */, "\u00D5" }, + { "Ö", "Ö"/* + * latin capital letter O with diaeresis + */, "\u00D6" }, { "×", "×"/* + * multiplication + * sign + */, "\u00D7" }, + { "Ø", "Ø"/* + * latin capital letter O with stroke = + * latin capital letter O slash + */, "\u00D8" }, { "Ù", "Ù"/* + * latin + * capital + * letter + * U + * with + * grave + */, "\u00D9" }, + { "Ú", "Ú"/* latin capital letter U with acute */, "\u00DA" }, + { "Û", "Û"/* + * latin capital letter U with circumflex + */, "\u00DB" }, { "Ü", "Ü"/* + * latin + * capital + * letter + * U + * with + * diaeresis + */, "\u00DC" }, + { "Ý", "Ý"/* latin capital letter Y with acute */, "\u00DD" }, + { "Þ", "Þ"/* latin capital letter THORN */, "\u00DE" }, + { "ß", "ß"/* + * latin small letter sharp s = ess-zed + */, "\u00DF" }, { "à", "à"/* + * latin + * small + * letter + * a + * with + * grave + * = + * latin + * small + * letter + * a + * grave + */, "\u00E0" }, + { "á", "á"/* + * latin small letter a with acute + */, "\u00E1" }, { "â", "â"/* + * latin + * small + * letter + * a + * with + * circumflex + */, "\u00E2" }, + { "ã", "ã"/* latin small letter a with tilde */, "\u00E3" }, + { "ä", "ä"/* latin small letter a with diaeresis */, "\u00E4" }, + { "å", "å"/* + * latin small letter a with ring above = + * latin small letter a ring + */, "\u00E5" }, { "æ", "æ"/* + * latin + * small + * letter + * ae = + * latin + * small + * ligature + * ae + */, "\u00E6" }, + { "ç", "ç"/* latin small letter c with cedilla */, "\u00E7" }, + { "è", "è"/* latin small letter e with grave */, "\u00E8" }, + { "é", "é"/* latin small letter e with acute */, "\u00E9" }, + { "ê", "ê"/* + * latin small letter e with circumflex + */, "\u00EA" }, { "ë", "ë"/* + * latin + * small + * letter + * e + * with + * diaeresis + */, "\u00EB" }, + { "ì", "ì"/* latin small letter i with grave */, "\u00EC" }, + { "í", "í"/* latin small letter i with acute */, "\u00ED" }, + { "î", "î"/* + * latin small letter i with circumflex + */, "\u00EE" }, { "ï", "ï"/* + * latin + * small + * letter + * i + * with + * diaeresis + */, "\u00EF" }, + { "ð", "ð"/* latin small letter eth */, "\u00F0" }, { "ñ", "ñ"/* + * latin + * small + * letter + * n + * with + * tilde + */, "\u00F1" }, + { "ò", "ò"/* latin small letter o with grave */, "\u00F2" }, + { "ó", "ó"/* latin small letter o with acute */, "\u00F3" }, + { "ô", "ô"/* + * latin small letter o with circumflex + */, "\u00F4" }, { "õ", "õ"/* + * latin + * small + * letter + * o + * with + * tilde + */, "\u00F5" }, + { "ö", "ö"/* latin small letter o with diaeresis */, "\u00F6" }, + { "÷", "÷"/* division sign */, "\u00F7" }, { "ø", "ø"/* + * latin + * small + * letter + * o + * with + * stroke + * = + * latin + * small + * letter + * o + * slash + */, "\u00F8" }, + { "ù", "ù"/* latin small letter u with grave */, "\u00F9" }, + { "ú", "ú"/* latin small letter u with acute */, "\u00FA" }, + { "û", "û"/* + * latin small letter u with circumflex + */, "\u00FB" }, { "ü", "ü"/* + * latin + * small + * letter + * u + * with + * diaeresis + */, "\u00FC" }, + { "ý", "ý"/* latin small letter y with acute */, "\u00FD" }, + { "þ", "þ"/* latin small letter thorn with */, "\u00FE" }, + { "ÿ", "ÿ"/* latin small letter y with diaeresis */, "\u00FF" }, + { "ƒ", "ƒ"/* + * latin small f with hook = function = + * florin + */, "\u0192" } + /* Greek */ + , { "Α", "Α"/* greek capital letter alpha */, "\u0391" }, + { "Β", "Β"/* greek capital letter beta */, "\u0392" }, { "Γ", "Γ"/* + * greek + * capital + * letter + * gamma + */, "\u0393" }, + { "Δ", "Δ"/* greek capital letter delta */, "\u0394" }, + { "Ε", "Ε"/* greek capital letter epsilon */, "\u0395" }, + { "Ζ", "Ζ"/* greek capital letter zeta */, "\u0396" }, { "Η", "Η"/* + * greek + * capital + * letter + * eta + */, "\u0397" }, + { "Θ", "Θ"/* greek capital letter theta */, "\u0398" }, { "Ι", "Ι"/* + * greek + * capital + * letter + * iota + */, "\u0399" }, + { "Κ", "Κ"/* greek capital letter kappa */, "\u039A" }, + { "Λ", "Λ"/* greek capital letter lambda */, "\u039B" }, { "Μ", "Μ"/* + * greek + * capital + * letter + * mu + */, "\u039C" }, + { "Ν", "Ν"/* greek capital letter nu */, "\u039D" }, { "Ξ", "Ξ"/* + * greek + * capital + * letter + * xi + */, "\u039E" }, + { "Ο", "Ο"/* greek capital letter omicron */, "\u039F" }, + { "Π", "Π"/* greek capital letter pi */, "\u03A0" }, { "Ρ", "Ρ"/* + * greek + * capital + * letter + * rho + */, "\u03A1" } + /* there is no Sigmaf and no \u03A2 */ + , { "Σ", "Σ"/* greek capital letter sigma */, "\u03A3" }, + { "Τ", "Τ"/* greek capital letter tau */, "\u03A4" }, + { "Υ", "Υ"/* greek capital letter upsilon */, "\u03A5" }, + { "Φ", "Φ"/* greek capital letter phi */, "\u03A6" }, { "Χ", "Χ"/* + * greek + * capital + * letter + * chi + */, "\u03A7" }, + { "Ψ", "Ψ"/* greek capital letter psi */, "\u03A8" }, { "Ω", "Ω"/* + * greek + * capital + * letter + * omega + */, "\u03A9" }, + { "α", "α"/* greek small letter alpha */, "\u03B1" }, { "β", "β"/* + * greek + * small + * letter + * beta + */, "\u03B2" }, + { "γ", "γ"/* greek small letter gamma */, "\u03B3" }, { "δ", "δ"/* + * greek + * small + * letter + * delta + */, "\u03B4" }, + { "ε", "ε"/* greek small letter epsilon */, "\u03B5" }, + { "ζ", "ζ"/* greek small letter zeta */, "\u03B6" }, { "η", "η"/* + * greek + * small + * letter + * eta + */, "\u03B7" }, + { "θ", "θ"/* greek small letter theta */, "\u03B8" }, { "ι", "ι"/* + * greek + * small + * letter + * iota + */, "\u03B9" }, + { "κ", "κ"/* greek small letter kappa */, "\u03BA" }, { "λ", "λ"/* + * greek + * small + * letter + * lambda + */, "\u03BB" }, + { "μ", "μ"/* greek small letter mu */, "\u03BC" }, { "ν", "ν"/* + * greek + * small + * letter + * nu + */, "\u03BD" }, + { "ξ", "ξ"/* greek small letter xi */, "\u03BE" }, { "ο", "ο"/* + * greek + * small + * letter + * omicron + */, "\u03BF" }, + { "π", "π"/* greek small letter pi */, "\u03C0" }, { "ρ", "ρ"/* + * greek + * small + * letter + * rho + */, "\u03C1" }, + { "ς", "ς"/* greek small letter final sigma */, "\u03C2" }, + { "σ", "σ"/* greek small letter sigma */, "\u03C3" }, { "τ", "τ"/* + * greek + * small + * letter + * tau + */, "\u03C4" }, + { "υ", "υ"/* greek small letter upsilon */, "\u03C5" }, + { "φ", "φ"/* greek small letter phi */, "\u03C6" }, { "χ", "χ"/* + * greek + * small + * letter + * chi + */, "\u03C7" }, + { "ψ", "ψ"/* greek small letter psi */, "\u03C8" }, { "ω", "ω"/* + * greek + * small + * letter + * omega + */, "\u03C9" }, + { "ϑ", "ϑ"/* greek small letter theta symbol */, "\u03D1" }, + { "ϒ", "ϒ"/* greek upsilon with hook symbol */, "\u03D2" }, { "ϖ", "ϖ"/* + * greek + * pi + * symbol + */, "\u03D6" } + /* General Punctuation */ + , { "•", "•"/* bullet = black small circle */, "\u2022" } + /* bullet is NOT the same as bullet operator ,"\u2219 */ + , { "…", "…"/* + * horizontal ellipsis = three dot + * leader + */, "\u2026" }, { "′", "′"/* + * prime + * = + * minutes + * = + * feet + */, "\u2032" }, + { "″", "″"/* double prime = seconds = inches */, "\u2033" }, + { "‾", "‾"/* overline = spacing overscore */, "\u203E" }, { "⁄", "⁄"/* + * fraction + * slash + */, "\u2044" } + /* Letterlike Symbols */ + , { "℘", "℘"/* + * script capital P = power set = + * Weierstrass p + */, "\u2118" }, { "ℑ", "ℑ"/* + * blackletter + * capital + * I + * = + * imaginary + * part + */, "\u2111" }, + { "ℜ", "ℜ"/* + * blackletter capital R = real part symbol + */, "\u211C" }, { "™", "™"/* + * trade + * mark + * sign + */, "\u2122" }, + { "ℵ", "ℵ"/* + * alef symbol = first transfinite + * cardinal + */, "\u2135" } + /* alef symbol is NOT the same as hebrew letter alef ,"\u05D0"} */ + /* Arrows */ + , { "←", "←"/* leftwards arrow */, "\u2190" }, { "↑", "↑"/* + * upwards + * arrow + */, "\u2191" }, + { "→", "→"/* rightwards arrow */, "\u2192" }, { "↓", "↓"/* + * downwards + * arrow + */, "\u2193" }, + { "↔", "↔"/* left right arrow */, "\u2194" }, { "↵", "↵"/* + * downwards + * arrow + * with + * corner + * leftwards + * = + * carriage + * return + */, "\u21B5" }, + { "⇐", "⇐"/* leftwards double arrow */, "\u21D0" } + /* + * Unicode does not say that lArr is the same as the 'is implied + * by' arrow but also does not have any other character for that + * function. So ? lArr can be used for 'is implied by' as + * ISOtech suggests + */ + , { "⇑", "⇑"/* upwards double arrow */, "\u21D1" }, { "⇒", "⇒"/* + * rightwards + * double + * arrow + */, "\u21D2" } + /* + * Unicode does not say this is the 'implies' character but does + * not have another character with this function so ? rArr can + * be used for 'implies' as ISOtech suggests + */ + , { "⇓", "⇓"/* downwards double arrow */, "\u21D3" }, { "⇔", "⇔"/* + * left + * right + * double + * arrow + */, "\u21D4" } + /* Mathematical Operators */ + , { "∀", "∀"/* for all */, "\u2200" }, { "∂", "∂"/* + * partial + * differential + */, "\u2202" }, + { "∃", "∃"/* there exists */, "\u2203" }, { "∅", "∅"/* + * empty + * set + * = + * null + * set + * = + * diameter + */, "\u2205" }, + { "∇", "∇"/* nabla = backward difference */, "\u2207" }, + { "∈", "∈"/* element of */, "\u2208" }, { "∉", "∉"/* + * not + * an + * element + * of + */, "\u2209" }, + { "∋", "∋"/* contains as member */, "\u220B" } + /* should there be a more memorable name than 'ni'? */ + , { "∏", "∏"/* n-ary product = product sign */, "\u220F" } + /* prod is NOT the same character as ,"\u03A0"} */ + , { "∑", "∑"/* n-ary sumation */, "\u2211" } + /* sum is NOT the same character as ,"\u03A3"} */ + , { "−", "−"/* minus sign */, "\u2212" }, { "∗", "∗"/* + * asterisk + * operator + */, "\u2217" }, + { "√", "√"/* square root = radical sign */, "\u221A" }, + { "∝", "∝"/* proportional to */, "\u221D" }, { "∞", "∞"/* infinity */, "\u221E" }, + { "∠", "∠"/* angle */, "\u2220" }, { "∧", "∧"/* + * logical + * and + * = + * wedge + */, "\u2227" }, + { "∨", "∨"/* logical or = vee */, "\u2228" }, { "∩", "∩"/* + * intersection + * = + * cap + */, "\u2229" }, + { "∪", "∪"/* union = cup */, "\u222A" }, { "∫", "∫"/* integral */, "\u222B" }, + { "∴", "∴"/* therefore */, "\u2234" }, { "∼", "∼"/* + * tilde + * operator + * = + * varies + * with + * = + * similar + * to + */, "\u223C" } + /* + * tilde operator is NOT the same character as the tilde + * ,"\u007E"} + */ + , { "≅", "≅"/* approximately equal to */, "\u2245" }, + { "≈", "≈"/* almost equal to = asymptotic to */, "\u2248" }, + { "≠", "≠"/* not equal to */, "\u2260" }, { "≡", "≡"/* + * identical + * to + */, "\u2261" }, + { "≤", "≤"/* less-than or equal to */, "\u2264" }, { "≥", "≥"/* + * greater + * - + * than + * or + * equal + * to + */, "\u2265" }, + { "⊂", "⊂"/* subset of */, "\u2282" }, { "⊃", "⊃"/* + * superset + * of + */, "\u2283" } + /* note that nsup 'not a superset of ,"\u2283"} */ + , { "⊆", "⊆"/* subset of or equal to */, "\u2286" }, { "⊇", "⊇"/* + * superset + * of + * or + * equal + * to + */, "\u2287" }, + { "⊕", "⊕"/* circled plus = direct sum */, "\u2295" }, + { "⊗", "⊗"/* circled times = vector product */, "\u2297" }, + { "⊥", "⊥"/* + * up tack = orthogonal to = perpendicular + */, "\u22A5" }, { "⋅", "⋅"/* + * dot + * operator + */, "\u22C5" } + /* + * dot operator is NOT the same character as ,"\u00B7"} /* + * Miscellaneous Technical + */ + , { "⌈", "⌈"/* left ceiling = apl upstile */, "\u2308" }, + { "⌉", "⌉"/* right ceiling */, "\u2309" }, { "⌊", "⌊"/* + * left + * floor + * = + * apl + * downstile + */, "\u230A" }, + { "⌋", "⌋"/* right floor */, "\u230B" }, { "⟨", "〈"/* + * left + * - + * pointing + * angle + * bracket + * = + * bra + */, "\u2329" } + /* lang is NOT the same character as ,"\u003C"} */ + , { "⟩", "〉"/* + * right-pointing angle bracket = ket + */, "\u232A" } + /* rang is NOT the same character as ,"\u003E"} */ + /* Geometric Shapes */ + , { "◊", "◊"/* lozenge */, "\u25CA" } + /* Miscellaneous Symbols */ + , { "♠", "♠"/* black spade suit */, "\u2660" } + /* black here seems to mean filled as opposed to hollow */ + , { "♣", "♣"/* black club suit = shamrock */, "\u2663" }, + { "♥", "♥"/* black heart suit = valentine */, "\u2665" }, + { "♦", "♦"/* black diamond suit */, "\u2666" }, { """, """ /* + * quotation + * mark + * = + * APL + * quote + */, "\"" }, + { "&", "&" /* ampersand */, "\u0026" }, { "<", "<" /* + * less + * - + * than + * sign + */, "\u003C" }, + { ">", ">" /* greater-than sign */, "\u003E" } + /* Latin Extended-A */ + , { "Œ", "Œ" /* latin capital ligature OE */, "\u0152" }, + { "œ", "œ" /* latin small ligature oe */, "\u0153" } + /* + * ligature is a misnomer this is a separate character in some + * languages + */ + , { "Š", "Š" /* + * latin capital letter S with caron + */, "\u0160" }, { "š", "š" /* + * latin + * small + * letter + * s + * with + * caron + */, "\u0161" }, + { "Ÿ", "Ÿ" /* + * latin capital letter Y with diaeresis + */, "\u0178" } + /* Spacing Modifier Letters */ + , { "ˆ", "ˆ" /* modifier letter circumflex accent */, "\u02C6" }, + { "˜", "˜" /* small tilde */, "\u02DC" } + /* General Punctuation */ + , { " ", " "/* en space */, "\u2002" }, { " ", " "/* + * em + * space + */, "\u2003" }, + { " ", " "/* thin space */, "\u2009" }, { "‌", "‌"/* + * zero + * width + * non + * - + * joiner + */, "\u200C" }, + { "‍", "‍"/* zero width joiner */, "\u200D" }, { "‎", "‎"/* + * left + * - + * to + * - + * right + * mark + */, "\u200E" }, + { "‏", "‏"/* right-to-left mark */, "\u200F" }, { "–", "–"/* + * en + * dash + */, "\u2013" }, + { "—", "—"/* em dash */, "\u2014" }, { "‘", "‘"/* + * left + * single + * quotation + * mark + */, "\u2018" }, + { "’", "’"/* right single quotation mark */, "\u2019" }, + { "‚", "‚"/* single low-9 quotation mark */, "\u201A" }, + { "“", "“"/* left double quotation mark */, "\u201C" }, + { "”", "”"/* right double quotation mark */, "\u201D" }, + { "„", "„"/* double low-9 quotation mark */, "\u201E" }, + { "†", "†"/* dagger */, "\u2020" }, { "‡", "‡"/* + * double + * dagger + */, "\u2021" }, + { "‰", "‰"/* per mille sign */, "\u2030" }, { "‹", "‹"/* + * single + * left + * - + * pointing + * angle + * quotation + * mark + */, "\u2039" } + /* lsaquo is proposed but not yet ISO standardized */ + , { "›", "›"/* + * single right-pointing angle quotation + * mark + */, "\u203A" } + /* rsaquo is proposed but not yet ISO standardized */ + , { "€", "€" /* euro sign */, "\u20AC" } }; + for (final String[] entity : entities) { + entityEscapeMap.put(entity[2], entity[0]); + escapeEntityMap.put(entity[0], entity[2]); + escapeEntityMap.put(entity[1], entity[2]); + } + } + + public static String escape(final String original) { + final StringBuffer buf = new StringBuffer(original); + escape(buf); + return buf.toString(); + } + + public static void escape(final StringBuffer original) { + int index = 0; + String escaped; + while (index < original.length()) { + escaped = entityEscapeMap.get(original.substring(index, index + 1)); + if (escaped != null) { + original.replace(index, index + 1, escaped); + index += escaped.length(); + } else { + index++; + } + } + } + + public static String unescape(final String original) { + String returnValue = null; + if (original != null) { + final StringBuffer buf = new StringBuffer(original); + unescape(buf); + returnValue = buf.toString(); + } + return returnValue; + } + + public static void unescape(final StringBuffer original) { + int index = 0; + int semicolonIndex; + String escaped; + String entity; + while (index < original.length()) { + index = original.indexOf("&", index); + if (-1 == index) { + break; + } + semicolonIndex = original.indexOf(";", index); + if (-1 != semicolonIndex) { + escaped = original.substring(index, semicolonIndex + 1); + entity = escapeEntityMap.get(escaped); + if (entity != null) { + original.replace(index, semicolonIndex + 1, entity); + } + index++; + } else { + break; + } + } + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HeaderMap.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HeaderMap.java new file mode 100644 index 00000000..5a933b82 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HeaderMap.java @@ -0,0 +1,38 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Created by mariotaku on 15/4/4. + */ +public class HeaderMap extends HashMap> { + + public void addHeader(String key, String value) { + List values = get(key); + if (values == null) values = new ArrayList<>(); + values.add(value); + put(key, values); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HostAddressResolver.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HostAddressResolver.java new file mode 100644 index 00000000..9e47526a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HostAddressResolver.java @@ -0,0 +1,10 @@ +package twitter4j.http; + +import java.io.IOException; +import java.net.InetAddress; + +public interface HostAddressResolver { + + public InetAddress[] resolve(String host) throws IOException; + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HostAddressResolverFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HostAddressResolverFactory.java new file mode 100644 index 00000000..cc1e1d02 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HostAddressResolverFactory.java @@ -0,0 +1,7 @@ +package twitter4j.http; + +public interface HostAddressResolverFactory { + + public HostAddressResolver getInstance(HttpClientConfiguration conf); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClient.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClient.java new file mode 100644 index 00000000..1a026251 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClient.java @@ -0,0 +1,31 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +import twitter4j.TwitterException; + +/** + * A utility class to handle HTTP request/response. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface HttpClient { + + HttpResponse request(HttpRequest req) throws TwitterException; + + void shutdown(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientBase.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientBase.java new file mode 100644 index 00000000..ce9b9c9d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientBase.java @@ -0,0 +1,69 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import java.io.DataOutputStream; +import java.io.IOException; + +import twitter4j.internal.logging.Logger; + +public class HttpClientBase { + + private static final Logger logger = Logger.getLogger(HttpClientBase.class); + protected final HttpClientConfiguration CONF; + + public HttpClientBase(final HttpClientConfiguration conf) { + CONF = conf; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof HttpClientBase)) return false; + + final HttpClientBase that = (HttpClientBase) o; + + if (!CONF.equals(that.CONF)) return false; + + return true; + } + + @Override + public int hashCode() { + return CONF.hashCode(); + } + + public void shutdown() { + } + + @Override + public String toString() { + return "HttpClientBase{" + "CONF=" + CONF + '}'; + } + + public void write(final DataOutputStream out, final String outStr) throws IOException { + out.writeBytes(outStr); + logger.debug(outStr); + } + + protected boolean isProxyConfigured() { + return CONF.getHttpProxyHost() != null && !CONF.getHttpProxyHost().equals(""); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientConfiguration.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientConfiguration.java new file mode 100644 index 00000000..3ce2eb4a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientConfiguration.java @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public interface HttpClientConfiguration { + + HostAddressResolverFactory getHostAddressResolverFactory(); + + HttpClientFactory getHttpClientFactory(); + + int getHttpConnectionTimeout(); + + int getHttpDefaultMaxPerRoute(); + + int getHttpMaxTotalConnections(); + + String getHttpProxyHost(); + + String getHttpProxyPassword(); + + int getHttpProxyPort(); + + String getHttpProxyUser(); + + int getHttpReadTimeout(); + + int getHttpRetryCount(); + + int getHttpRetryIntervalSeconds(); + + String getHttpUserAgent(); + + boolean isGZIPEnabled(); + + boolean isPrettyDebugEnabled(); + + boolean isProxyConfigured(); + + boolean isSSLEnabled(); + + boolean isSSLErrorIgnored(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientFactory.java new file mode 100644 index 00000000..81e6b4a0 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +public interface HttpClientFactory { + + public HttpClient getInstance(HttpClientConfiguration conf); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java new file mode 100644 index 00000000..7c5f2dce --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java @@ -0,0 +1,68 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import java.util.HashMap; +import java.util.Map; + +import twitter4j.TwitterException; +import twitter4j.conf.ConfigurationContext; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +public class HttpClientImpl extends HttpClientBase implements HttpClient, HttpResponseCode { + + private static final Map instanceMap = new HashMap<>( + 1); + + public HttpClientImpl() { + super(ConfigurationContext.getInstance()); + } + + public HttpClientImpl(final HttpClientConfiguration conf) { + super(conf); + } + + public HttpResponse get(final String url, final String sign_url) throws TwitterException { + return request(new HttpRequest(RequestMethod.GET, url, sign_url, null, null, null)); + } + + public HttpResponse post(final String url, final String sign_url, final HttpParameter[] params) + throws TwitterException { + return request(new HttpRequest(RequestMethod.POST, url, sign_url, params, null, null)); + } + + @Override + public HttpResponse request(final HttpRequest req) throws TwitterException { + throw new UnsupportedOperationException(); + } + + public static HttpClient getInstance(final HttpClientConfiguration conf) { + HttpClient client = instanceMap.get(conf); + if (null == client) { + client = new HttpClientImpl(conf); + instanceMap.put(conf, client); + } + return client; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientWrapper.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientWrapper.java new file mode 100644 index 00000000..55ae1614 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientWrapper.java @@ -0,0 +1,250 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import twitter4j.TwitterException; +import twitter4j.auth.Authorization; +import twitter4j.conf.Configuration; +import twitter4j.conf.ConfigurationContext; + +import static twitter4j.http.RequestMethod.DELETE; +import static twitter4j.http.RequestMethod.GET; +import static twitter4j.http.RequestMethod.HEAD; +import static twitter4j.http.RequestMethod.POST; +import static twitter4j.http.RequestMethod.PUT; + +/** + * HTTP Client wrapper with handy request methods, ResponseListener mechanism + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class HttpClientWrapper { + private final Configuration wrapperConf; + private final HttpClient http; + + private final Map> requestHeaders; + + private HttpResponseListener httpResponseListener; + + // never used with this project. Just for handiness for those using this + // class. + public HttpClientWrapper() { + wrapperConf = ConfigurationContext.getInstance(); + requestHeaders = wrapperConf.getRequestHeaders(); + http = FactoryUtils.getHttpClient(wrapperConf); + } + + public HttpClientWrapper(final Configuration wrapperConf) { + this.wrapperConf = wrapperConf; + requestHeaders = wrapperConf.getRequestHeaders(); + http = FactoryUtils.getHttpClient(wrapperConf); + } + + public HttpResponse delete(final String url, final String signUrl) throws TwitterException { + return delete(url, signUrl, null, null); + } + + public HttpResponse delete(final String url, final String signUrl, final Authorization authorization) + throws TwitterException { + return delete(url, signUrl, null, authorization); + } + + public HttpResponse delete(final String url, final String signUrl, final HttpParameter[] parameters) + throws TwitterException { + return delete(url, signUrl, parameters, null); + } + + public HttpResponse delete(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization) throws TwitterException { + return request(new HttpRequest(DELETE, url, signUrl, parameters, authorization, requestHeaders)); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final HttpClientWrapper that = (HttpClientWrapper) o; + + if (!http.equals(that.http)) return false; + if (!requestHeaders.equals(that.requestHeaders)) return false; + if (!wrapperConf.equals(that.wrapperConf)) return false; + + return true; + } + + public HttpResponse get(final String url, final String signUrl) throws TwitterException { + return get(url, signUrl, null, null, null); + } + + public HttpResponse get(final String url, final String signUrl, final Authorization authorization) + throws TwitterException { + return get(url, signUrl, null, authorization); + } + + public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters) + throws TwitterException { + return get(url, signUrl, parameters, null, null); + } + + public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization) throws TwitterException { + return get(url, signUrl, parameters, authorization, null); + } + + public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters, + final Map> requestHeaders) throws TwitterException { + return get(url, signUrl, parameters, null, requestHeaders); + } + + public HttpResponse get(final String url, final String signUrl, final Map> requestHeaders) + throws TwitterException { + return get(url, signUrl, null, null, requestHeaders); + } + + public HttpResponse get(final String url, final String signUrl, final Authorization authorization, + final Map> requestHeaders) throws TwitterException { + return get(url, signUrl, null, authorization, requestHeaders); + } + + public HttpResponse get(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization, final Map> requestHeaders) + throws TwitterException { + final Map> headers = new HashMap<>(this.requestHeaders); + if (requestHeaders != null) { + headers.putAll(requestHeaders); + } + return request(new HttpRequest(GET, url, signUrl, parameters, authorization, headers)); + } + + @Override + public int hashCode() { + int result = wrapperConf.hashCode(); + result = 31 * result + http.hashCode(); + result = 31 * result + requestHeaders.hashCode(); + return result; + } + + public HttpResponse head(final String url, final String signUrl) throws TwitterException { + return head(url, signUrl, null, null); + } + + public HttpResponse head(final String url, final String signUrl, final Authorization authorization) + throws TwitterException { + return head(url, signUrl, null, authorization); + } + + public HttpResponse head(final String url, final String signUrl, final HttpParameter[] parameters) + throws TwitterException { + return head(url, signUrl, parameters, null); + } + + public HttpResponse head(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization) throws TwitterException { + return request(new HttpRequest(HEAD, url, signUrl, parameters, authorization, requestHeaders)); + } + + public HttpResponse post(final String url, final String signUrl) throws TwitterException { + return post(url, signUrl, null, null, null); + } + + public HttpResponse post(final String url, final String signUrl, final Authorization authorization) + throws TwitterException { + return post(url, signUrl, null, authorization, null); + } + + public HttpResponse post(final String url, final String signUrl, final HttpParameter[] parameters) + throws TwitterException { + return post(url, signUrl, parameters, null, null); + } + + public HttpResponse post(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization) throws TwitterException { + return post(url, signUrl, parameters, authorization, null); + } + + public HttpResponse post(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization, final Map> requestHeaders) throws TwitterException { + final Map> headers = new HashMap<>(this.requestHeaders); + if (requestHeaders != null) { + headers.putAll(requestHeaders); + } + return request(new HttpRequest(POST, url, signUrl, parameters, authorization, headers)); + } + + public HttpResponse post(final String url, final String signUrl, final HttpParameter[] parameters, + final Map> requestHeaders) throws TwitterException { + return post(url, signUrl, parameters, null, requestHeaders); + } + + public HttpResponse put(final String url, final String signUrl) throws TwitterException { + return put(url, signUrl, null, null); + } + + public HttpResponse put(final String url, final String signUrl, final Authorization authorization) + throws TwitterException { + return put(url, signUrl, null, authorization); + } + + public HttpResponse put(final String url, final String signUrl, final HttpParameter[] parameters) + throws TwitterException { + return put(url, signUrl, parameters, null); + } + + public HttpResponse put(final String url, final String signUrl, final HttpParameter[] parameters, + final Authorization authorization) throws TwitterException { + return request(new HttpRequest(PUT, url, signUrl, parameters, authorization, requestHeaders)); + } + + public void setHttpResponseListener(final HttpResponseListener listener) { + httpResponseListener = listener; + } + + public void shutdown() { + http.shutdown(); + } + + @Override + public String toString() { + return "HttpClientWrapper{" + "wrapperConf=" + wrapperConf + ", http=" + http + ", requestHeaders=" + + requestHeaders + ", httpResponseListener=" + httpResponseListener + '}'; + } + + private HttpResponse request(final HttpRequest req) throws TwitterException { + HttpResponse res; + try { + res = http.request(req); + // fire HttpResponseEvent + if (httpResponseListener != null) { + httpResponseListener.httpResponseReceived(new HttpResponseEvent(req, res, null)); + } + } catch (final TwitterException te) { + if (httpResponseListener != null) { + httpResponseListener.httpResponseReceived(new HttpResponseEvent(req, null, te)); + } + throw te; + } + return res; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientWrapperConfiguration.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientWrapperConfiguration.java new file mode 100644 index 00000000..eb79febd --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpClientWrapperConfiguration.java @@ -0,0 +1,27 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +import java.util.List; +import java.util.Map; + +public interface HttpClientWrapperConfiguration extends HttpClientConfiguration { + /** + * @return request headers + */ + HeaderMap getRequestHeaders(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpParameter.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpParameter.java new file mode 100644 index 00000000..22c8effe --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpParameter.java @@ -0,0 +1,302 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +import java.io.File; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.List; +import java.util.Locale; + +/** + * A data class representing HTTP Post parameter + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class HttpParameter implements Comparable { + private String name = null; + private String value = null; + private String fileName = null; + private File file = null; + private InputStream fileBody = null; + private String overrideFileType; + + private static final String JPEG = "image/jpeg"; + + private static final String GIF = "image/gif"; + + private static final String PNG = "image/png"; + + private static final String OCTET = "application/octet-stream"; + + public HttpParameter(final String name, final boolean value) { + this.name = name; + this.value = String.valueOf(value); + } + + public HttpParameter(final String name, final double value) { + this.name = name; + this.value = String.valueOf(value); + } + + public HttpParameter(final String name, final File file) { + this(name, file, null); + } + + public HttpParameter(final String name, final File file, final String overrideContentType) { + this.name = name; + this.file = file; + overrideFileType = overrideContentType; + } + + public HttpParameter(final String name, final int value) { + this.name = name; + this.value = String.valueOf(value); + } + + public HttpParameter(final String name, final long value) { + this.name = name; + this.value = String.valueOf(value); + } + + public HttpParameter(final String name, final String value) { + this.name = name; + this.value = value; + } + + public HttpParameter(final String name, final String fileName, final InputStream fileBody) { + this(name, fileName, fileBody, null); + } + + public HttpParameter(final String name, final String fileName, final InputStream fileBody, + final String overrideFileType) { + this.name = name; + this.fileName = fileName; + this.fileBody = fileBody; + this.overrideFileType = overrideFileType; + } + + @Override + public int compareTo(final HttpParameter o) { + int compared; + final HttpParameter that = o; + compared = name.compareTo(that.name); + if (0 == compared) { + compared = value.compareTo(that.value); + } + return compared; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof HttpParameter)) return false; + + final HttpParameter that = (HttpParameter) o; + + if (file != null ? !file.equals(that.file) : that.file != null) return false; + if (fileBody != null ? !fileBody.equals(that.fileBody) : that.fileBody != null) + return false; + if (!name.equals(that.name)) return false; + if (value != null ? !value.equals(that.value) : that.value != null) return false; + + return true; + } + + /** + * @return content-type + */ + public String getContentType() { + if (!isFile()) throw new IllegalStateException("not a file"); + if (overrideFileType != null) return overrideFileType; + String contentType; + String extensions = getFileName(); + final int index = extensions.lastIndexOf("."); + if (-1 == index) { + // no extension + contentType = OCTET; + } else { + extensions = extensions.substring(extensions.lastIndexOf(".") + 1).toLowerCase(Locale.US); + if (extensions.length() == 3) { + if ("gif".equals(extensions)) { + contentType = GIF; + } else if ("png".equals(extensions)) { + contentType = PNG; + } else if ("jpg".equals(extensions)) { + contentType = JPEG; + } else { + contentType = OCTET; + } + } else if (extensions.length() == 4) { + if ("jpeg".equals(extensions)) { + contentType = JPEG; + } else { + contentType = OCTET; + } + } else { + contentType = OCTET; + } + } + return contentType; + } + + public File getFile() { + return file; + } + + public InputStream getFileBody() { + return fileBody; + } + + public String getFileName() { + return file != null ? file.getName() : fileName; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public boolean hasFileBody() { + return fileBody != null; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + (file != null ? file.hashCode() : 0); + result = 31 * result + (fileBody != null ? fileBody.hashCode() : 0); + return result; + } + + public boolean isFile() { + return fileBody != null || file != null; + } + + @Override + public String toString() { + return "PostParameter{" + "name='" + name + '\'' + ", value='" + value + '\'' + ", file=" + file + + ", fileBody=" + fileBody + '}'; + } + + public static boolean containsFile(final HttpParameter[] params) { + boolean containsFile = false; + if (null == params) return false; + for (final HttpParameter param : params) { + if (param.isFile()) { + containsFile = true; + break; + } + } + return containsFile; + } + + /** + * @param value string to be encoded + * @return encoded string + * @see OAuth / TestCases + * @see Space + * encoding - OAuth | Google Groups + * @see RFC 3986 - + * Uniform Resource Identifier (URI): Generic Syntax - 2.1. + * Percent-Encoding + */ + public static String encode(final String value) { + String encoded; + try { + encoded = URLEncoder.encode(value, "UTF-8"); + } catch (final UnsupportedEncodingException ignore) { + return null; + } + final StringBuilder buf = new StringBuilder(encoded.length()); + char focus; + for (int i = 0; i < encoded.length(); i++) { + focus = encoded.charAt(i); + if (focus == '*') { + buf.append("%2A"); + } else if (focus == '+') { + buf.append("%20"); + } else if (focus == '%' && i + 1 < encoded.length() && encoded.charAt(i + 1) == '7' + && encoded.charAt(i + 2) == 'E') { + buf.append('~'); + i += 2; + } else { + buf.append(focus); + } + } + return buf.toString(); + } + + public static String encodeParameters(final HttpParameter[] httpParams) { + if (null == httpParams) return ""; + final StringBuilder buf = new StringBuilder(); + for (int j = 0; j < httpParams.length; j++) { + if (httpParams[j].isFile()) + throw new IllegalArgumentException("parameter [" + httpParams[j].name + "]should be text"); + if (j != 0) { + buf.append("&"); + } + buf.append(encode(httpParams[j].name)).append("=").append(encode(httpParams[j].value)); + } + return buf.toString(); + } + + public static HttpParameter[] getParameterArray(final String name, final int value) { + return getParameterArray(name, String.valueOf(value)); + } + + public static HttpParameter[] getParameterArray(final String name1, final int value1, final String name2, + final int value2) { + return getParameterArray(name1, String.valueOf(value1), name2, String.valueOf(value2)); + } + + public static HttpParameter[] getParameterArray(final String name, final String value) { + return new HttpParameter[]{new HttpParameter(name, value)}; + } + + public static HttpParameter[] getParameterArray(final String name1, final String value1, final String name2, + final String value2) { + return new HttpParameter[]{new HttpParameter(name1, value1), new HttpParameter(name2, value2)}; + } + + public static HttpParameter[] merge(final HttpParameter[] params, final HttpParameter... extraParams) { + if (params == null) return extraParams; + if (extraParams == null) return params; + final HttpParameter[] merged = new HttpParameter[params.length + extraParams.length]; + System.arraycopy(params, 0, merged, 0, params.length); + System.arraycopy(extraParams, 0, merged, params.length, extraParams.length); + return merged; + } + + /* package */ + static boolean containsFile(final List params) { + boolean containsFile = false; + for (final HttpParameter param : params) { + if (param.isFile()) { + containsFile = true; + break; + } + } + return containsFile; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpRequest.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpRequest.java new file mode 100644 index 00000000..508fb92c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpRequest.java @@ -0,0 +1,133 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import twitter4j.auth.Authorization; + +/** + * HTTP Request parameter object + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class HttpRequest { + + private final RequestMethod method; + + private final String url, signUrl; + + private final HttpParameter[] parameters; + + private final Authorization authorization; + + private final Map> requestHeaders; + + private static final HttpParameter[] NULL_PARAMETERS = new HttpParameter[0]; + + /** + * @param method Specifies the HTTP method + * @param url the request to request + * @param parameters parameters + * @param authorization Authentication implementation. Currently + * BasicAuthentication, OAuthAuthentication and + * NullAuthentication are supported. + * @param requestHeaders + */ + public HttpRequest(final RequestMethod method, final String url, final String signUrl, + final HttpParameter[] parameters, final Authorization authorization, + final Map> requestHeaders) { + this.method = method; + if (method != RequestMethod.POST && parameters != null && parameters.length != 0) { + final String paramString = HttpParameter.encodeParameters(parameters); + this.url = url + "?" + paramString; + this.signUrl = signUrl + "?" + paramString; + this.parameters = NULL_PARAMETERS; + } else { + this.url = url; + this.signUrl = signUrl; + this.parameters = parameters; + } + this.authorization = authorization; + this.requestHeaders = requestHeaders; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final HttpRequest that = (HttpRequest) o; + + if (authorization != null ? !authorization.equals(that.authorization) : that.authorization != null) + return false; + if (!Arrays.equals(parameters, that.parameters)) return false; + if (requestHeaders != null ? !requestHeaders.equals(that.requestHeaders) : that.requestHeaders != null) + return false; + if (method != null ? !method.equals(that.method) : that.method != null) return false; + if (url != null ? !url.equals(that.url) : that.url != null) return false; + + return true; + } + + public Authorization getAuthorization() { + return authorization; + } + + public RequestMethod getMethod() { + return method; + } + + public HttpParameter[] getParameters() { + return parameters; + } + + public Map> getRequestHeaders() { + return requestHeaders; + } + + public String getSignURL() { + return signUrl != null ? signUrl : url; + } + + public String getURL() { + return url; + } + + @Override + public int hashCode() { + int result = method != null ? method.hashCode() : 0; + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (signUrl != null ? signUrl.hashCode() : 0); + result = 31 * result + (parameters != null ? Arrays.hashCode(parameters) : 0); + result = 31 * result + (authorization != null ? authorization.hashCode() : 0); + result = 31 * result + (requestHeaders != null ? requestHeaders.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "HttpRequest{" + "requestMethod=" + method + ", url='" + url + '\'' + ", signUrl='" + signUrl + '\'' + + ", postParams=" + (parameters == null ? null : Arrays.asList(parameters)) + ", authentication=" + + authorization + ", requestHeaders=" + requestHeaders + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponse.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponse.java new file mode 100644 index 00000000..a9915937 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponse.java @@ -0,0 +1,229 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.List; +import java.util.Map; + +import twitter4j.TwitterException; +import twitter4j.conf.ConfigurationContext; +import twitter4j.internal.logging.Logger; + +/** + * A data class representing HTTP Response + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public abstract class HttpResponse { + private static final Logger logger = Logger.getLogger(HttpResponse.class); + protected final HttpClientConfiguration CONF; + + protected int statusCode; + + protected String responseAsString = null; + + protected InputStream is; + private boolean streamConsumed = false; + private JSONObject json = null; + private JSONArray jsonArray = null; + + public HttpResponse(final HttpClientConfiguration conf) { + CONF = conf; + } + + HttpResponse() { + CONF = ConfigurationContext.getInstance(); + } + + /** + * Returns the response body as twitter4j.internal.org.json.JSONArray.
+ * Disconnects the internal HttpURLConnection silently. + * + * @return response body as twitter4j.internal.org.json.JSONArray + * @throws TwitterException + */ + public JSONArray asJSONArray() throws TwitterException { + if (jsonArray == null) { + try { + if (responseAsString == null) { + responseAsString = asString(); + } + jsonArray = new JSONArray(responseAsString); + if (CONF.isPrettyDebugEnabled()) { + logger.debug(jsonArray.toString(1)); + } else { + logger.debug(responseAsString != null ? responseAsString : jsonArray.toString()); + } + } catch (final JSONException jsone) { + if (logger.isDebugEnabled()) + throw new TwitterException(jsone.getMessage() + ":" + responseAsString, jsone); + else + throw new TwitterException(jsone.getMessage(), jsone); + } finally { + disconnectForcibly(); + } + } + return jsonArray; + } + + /** + * Returns the response body as twitter4j.internal.org.json.JSONObject.
+ * Disconnects the internal HttpURLConnection silently. + * + * @return response body as twitter4j.internal.org.json.JSONObject + * @throws TwitterException + */ + public JSONObject asJSONObject() throws TwitterException { + if (json == null) { + try { + if (responseAsString == null) { + responseAsString = asString(); + } + json = new JSONObject(responseAsString); + if (CONF.isPrettyDebugEnabled()) { + logger.debug(json.toString(1)); + } else { + logger.debug(responseAsString != null ? responseAsString : json.toString()); + } + } catch (final JSONException jsone) { + if (responseAsString == null) + throw new TwitterException(jsone.getMessage(), jsone); + else + throw new TwitterException(jsone.getMessage() + ":" + responseAsString, jsone); + } finally { + disconnectForcibly(); + } + } + return json; + } + + public Reader asReader() { + try { + return new BufferedReader(new InputStreamReader(is, "UTF-8")); + } catch (final java.io.UnsupportedEncodingException uee) { + return new InputStreamReader(is); + } + } + + /** + * Returns the response stream.
+ * This method cannot be called after calling asString() or asDcoument()
+ * It is suggested to call disconnect() after consuming the stream. + *

+ * Disconnects the internal HttpURLConnection silently. + * + * @return response body stream + * @throws TwitterException + * @see #disconnect() + */ + public InputStream asStream() { + if (streamConsumed) throw new IllegalStateException("Stream has already been consumed."); + return is; + } + + /** + * Returns the response body as string.
+ * Disconnects the internal HttpURLConnection silently. + * + * @return response body + * @throws TwitterException + */ + public String asString() throws TwitterException { + if (null == responseAsString) { + BufferedReader br = null; + InputStream stream = null; + try { + stream = asStream(); + if (null == stream) return null; + br = new BufferedReader(new InputStreamReader(stream, "UTF-8")); + final StringBuilder buf = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + buf.append(line).append("\n"); + } + responseAsString = buf.toString(); + logger.debug(responseAsString); + stream.close(); + streamConsumed = true; + } catch (final OutOfMemoryError oome) { + throw new TwitterException(oome.getMessage(), oome); + } catch (final IOException ioe) { + throw new TwitterException(ioe.getMessage(), ioe); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (final IOException ignore) { + } + } + if (br != null) { + try { + br.close(); + } catch (final IOException ignore) { + } + } + disconnectForcibly(); + } + } + return responseAsString; + } + + public abstract void disconnect() throws IOException; + + public long getContentLength() { + try { + return Long.parseLong(getResponseHeader("Content-Length")); + } catch (final Exception e) { + return -1; + } + } + + public abstract String getResponseHeader(String name); + + public abstract List getResponseHeaders(String name); + + public abstract Map> getResponseHeaderFields(); + + public int getStatusCode() { + return statusCode; + } + + @Override + public String toString() { + return "HttpResponse{" + "statusCode=" + statusCode + ", responseAsString='" + responseAsString + '\'' + + ", is=" + is + ", streamConsumed=" + streamConsumed + '}'; + } + + private void disconnectForcibly() { + try { + disconnect(); + } catch (final Exception ignore) { + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseCode.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseCode.java new file mode 100644 index 00000000..4ad9dc3c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseCode.java @@ -0,0 +1,89 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +public interface HttpResponseCode { + /** OK: Success! **/ + int OK = 200; + int CREATED = 201; + int ACCEPTED = 202; + int MULTIPLE_CHOICES = 300;// + int FOUND = 302;// + /** Not Modified: There was no new data to return. **/ + int NOT_MODIFIED = 304; + /** + * Bad Request: The request was invalid. An accompanying error message will + * explain why. This is the status code will be returned during rate + * limiting. + **/ + int BAD_REQUEST = 400; + /** Not Authorized: Authentication credentials were missing or incorrect. **/ + int UNAUTHORIZED = 401; + /** + * Forbidden: The request is understood, but it has been refused. An + * accompanying error message will explain why. + **/ + int FORBIDDEN = 403; + /** + * Not Found: The URI requested is invalid or the resource requested, such + * as a user, does not exists. + **/ + int NOT_FOUND = 404; + /** + * Not Acceptable: Returned by the Search API when an invalid format is + * specified in the request. + **/ + int NOT_ACCEPTABLE = 406; + /** + * Enhance Your Calm: Returned by the Search and Trends API when you are + * being rate limited. Not registered in RFC. + **/ + int ENHANCE_YOUR_CLAIM = 420; + /** + * Returned when an image uploaded to POST account/update_profile_banner is + * unable to be processed. + **/ + int UNPROCESSABLE_ENTITY = 422; + /** + * Returned in API v1.1 when a request cannot be served due to the + * application's rate limit having been exhausted for the resource. See Rate + * Limiting in API v1.1. + **/ + int TOO_MANY_REQUESTS = 429; + /** + * Internal Server Error: Something is broken. Please post to the group so + * the Twitter team can investigate. + **/ + int INTERNAL_SERVER_ERROR = 500; + /** Bad Gateway: Twitter is down or being upgraded. **/ + int BAD_GATEWAY = 502; + /** + * Service Unavailable: The Twitter servers are up, but overloaded with + * requests. Try again later. The search and trend methods use this to + * indicate when you are being rate limited. + **/ + int SERVICE_UNAVAILABLE = 503; + /** + * The Twitter servers are up, but the request couldn't be serviced due to + * some failure within our stack. Try again later. + **/ + int GATEWAY_TIMEOUT = 504; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseEvent.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseEvent.java new file mode 100644 index 00000000..542b3e77 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseEvent.java @@ -0,0 +1,93 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +import twitter4j.TwitterException; + +/** + * @author Andrew Hedges - andrew.hedges at gmail.com + */ +public final class HttpResponseEvent { + + private final HttpRequest request; + + private final HttpResponse response; + + private final TwitterException twitterException; + + HttpResponseEvent(final HttpRequest request, final HttpResponse response, final TwitterException te) { + this.request = request; + this.response = response; + twitterException = te; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final HttpResponseEvent that = (HttpResponseEvent) o; + + if (request != null ? !request.equals(that.request) : that.request != null) return false; + if (response != null ? !response.equals(that.response) : that.response != null) return false; + + return true; + } + + /** + * returns the request associated with the event + * + * @return the request associated with the event + */ + public HttpRequest getRequest() { + return request; + } + + /** + * returns the response associated with the event + * + * @return the response associated with the event + */ + public HttpResponse getResponse() { + return response; + } + + /** + * returns the TwitterException associated with the event + * + * @return the TwitterException associated with the event + */ + public TwitterException getTwitterException() { + return twitterException; + } + + @Override + public int hashCode() { + int result = request != null ? request.hashCode() : 0; + result = 31 * result + (response != null ? response.hashCode() : 0); + return result; + } + + public boolean isAuthenticated() { + return request.getAuthorization().isEnabled(); + } + + @Override + public String toString() { + return "HttpResponseEvent{" + "request=" + request + ", response=" + response + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseListener.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseListener.java new file mode 100644 index 00000000..ab7968d0 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/HttpResponseListener.java @@ -0,0 +1,10 @@ +package twitter4j.http; + +/** + * @author Andrew Hedges - andrew.hedges at gmail.com + */ +public interface HttpResponseListener { + + public void httpResponseReceived(HttpResponseEvent event); + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/RequestMethod.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/RequestMethod.java new file mode 100644 index 00000000..fc56c331 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/RequestMethod.java @@ -0,0 +1,35 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.http; + +/** + * @author Dan Checkoway - dcheckoway at gmail.com + */ +public enum RequestMethod { + + GET("GET"), POST("POST"), DELETE("DELETE"), HEAD("HEAD"), PUT("PUT"); + + private final String method; + + private RequestMethod(final String method) { + this.method = method; + } + + public String getMethod() { + return method; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/http/StreamingGZIPInputStream.java b/firetweet.component.twitter4j/src/main/java/twitter4j/http/StreamingGZIPInputStream.java new file mode 100644 index 00000000..e57b457b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/http/StreamingGZIPInputStream.java @@ -0,0 +1,50 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.http; + +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; + +public final class StreamingGZIPInputStream extends GZIPInputStream { + + private final InputStream wrapped; + + public StreamingGZIPInputStream(final InputStream is) throws IOException { + super(is); + wrapped = is; + } + + /** + * Overrides behavior of GZIPInputStream which assumes we have all the data + * available which is not true for streaming. We instead rely on the + * underlying stream to tell us how much data is available. + *

+ * Programs should not count on this method to return the actual number of + * bytes that could be read without blocking. + * + * @return - whatever the wrapped InputStream returns + * @exception java.io.IOException if an I/O error occurs. + */ + @Override + public int available() throws IOException { + return wrapped.available(); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/AccountSettingsJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/AccountSettingsJSONImpl.java new file mode 100644 index 00000000..5f52c2b1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/AccountSettingsJSONImpl.java @@ -0,0 +1,133 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.AccountSettings; +import twitter4j.Location; +import twitter4j.TimeZone; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +class AccountSettingsJSONImpl extends TwitterResponseImpl implements AccountSettings { + + /** + * + */ + private static final long serialVersionUID = -3364568117893571939L; + private final boolean SLEEP_TIME_ENABLED; + private final String SLEEP_START_TIME; + private final String SLEEP_END_TIME; + private final Location[] TREND_LOCATION; + private final boolean GEO_ENABLED; + private final String LANGUAGE; + private final TimeZone TIMEZONE; + private final boolean ALWAYS_USE_HTTPS; + private final boolean DISCOVERABLE_BY_EMAIL; + + private AccountSettingsJSONImpl(final HttpResponse res, final JSONObject json) throws TwitterException { + super(res); + try { + final JSONObject sleepTime = json.getJSONObject("sleep_time"); + SLEEP_TIME_ENABLED = getBoolean("enabled", sleepTime); + SLEEP_START_TIME = sleepTime.getString("start_time"); + SLEEP_END_TIME = sleepTime.getString("end_time"); + if (json.isNull("trend_location")) { + TREND_LOCATION = new Location[0]; + } else { + final JSONArray locations = json.getJSONArray("trend_location"); + TREND_LOCATION = new Location[locations.length()]; + for (int i = 0; i < locations.length(); i++) { + TREND_LOCATION[i] = new LocationJSONImpl(locations.getJSONObject(i)); + } + } + GEO_ENABLED = getBoolean("geo_enabled", json); + LANGUAGE = json.getString("language"); + ALWAYS_USE_HTTPS = getBoolean("always_use_https", json); + DISCOVERABLE_BY_EMAIL = getBoolean("discoverable_by_email", json); + TIMEZONE = new TimeZoneJSONImpl(json.getJSONObject("time_zone")); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + /* package */AccountSettingsJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + this(res, res.asJSONObject()); + } + + /* package */AccountSettingsJSONImpl(final JSONObject json) throws TwitterException { + this(null, json); + } + + @Override + public String getLanguage() { + return LANGUAGE; + } + + @Override + public String getSleepEndTime() { + return SLEEP_END_TIME; + } + + @Override + public String getSleepStartTime() { + return SLEEP_START_TIME; + } + + @Override + public TimeZone getTimeZone() { + return TIMEZONE; + } + + @Override + public Location[] getTrendLocations() { + return TREND_LOCATION; + } + + @Override + public boolean isAlwaysUseHttps() { + return ALWAYS_USE_HTTPS; + } + + @Override + public boolean isDiscoverableByEmail() { + return DISCOVERABLE_BY_EMAIL; + } + + @Override + public boolean isGeoEnabled() { + return GEO_ENABLED; + } + + @Override + public boolean isSleepTimeEnabled() { + return SLEEP_TIME_ENABLED; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/AccountTotalsJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/AccountTotalsJSONImpl.java new file mode 100644 index 00000000..76bb76fc --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/AccountTotalsJSONImpl.java @@ -0,0 +1,111 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONObject; + +import twitter4j.AccountTotals; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getInt; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +class AccountTotalsJSONImpl extends TwitterResponseImpl implements AccountTotals { + + /** + * + */ + private static final long serialVersionUID = 1766976816658998807L; + private final int updates; + private final int followers; + private final int favorites; + private final int friends; + + private AccountTotalsJSONImpl(final HttpResponse res, final JSONObject json) { + super(res); + updates = getInt("updates", json); + followers = getInt("followers", json); + favorites = getInt("favorites", json); + friends = getInt("friends", json); + } + + /* package */AccountTotalsJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + this(res, res.asJSONObject()); + } + + /* package */AccountTotalsJSONImpl(final JSONObject json) throws TwitterException { + this(null, json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final AccountTotalsJSONImpl that = (AccountTotalsJSONImpl) o; + + if (favorites != that.favorites) return false; + if (followers != that.followers) return false; + if (friends != that.friends) return false; + if (updates != that.updates) return false; + + return true; + } + + @Override + public int getFavorites() { + return favorites; + } + + @Override + public int getFollowers() { + return followers; + } + + @Override + public int getFriends() { + return friends; + } + + @Override + public int getUpdates() { + return updates; + } + + @Override + public int hashCode() { + int result = updates; + result = 31 * result + followers; + result = 31 * result + favorites; + result = 31 * result + friends; + return result; + } + + @Override + public String toString() { + return "AccountTotalsJSONImpl{" + "updates=" + updates + ", followers=" + followers + ", favorites=" + + favorites + ", friends=" + friends + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/ActivityJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/ActivityJSONImpl.java new file mode 100644 index 00000000..bd88a84d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/ActivityJSONImpl.java @@ -0,0 +1,236 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.Date; + +import twitter4j.Activity; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; +import twitter4j.User; +import twitter4j.UserList; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getDate; +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +class ActivityJSONImpl extends TwitterResponseImpl implements Activity { + + /** + * + */ + private static final long serialVersionUID = -8200474717252861878L; + + private Action action; + + private Date createdAt; + + private User[] sources, targetUsers; + + private Status[] targetObjectStatuses, targetStatuses; + + private UserList[] targetUserLists, targetObjectUserLists; + + private long maxPosition, minPosition; + + private int targetObjectsSize, targetsSize, sourcesSize; + + /* package */ActivityJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public int compareTo(final Activity another) { + if (another == null) return 0; + final Date thisDate = getCreatedAt(), thatDate = another.getCreatedAt(); + if (thisDate == null || thatDate == null) return 0; + return thisDate.compareTo(thatDate); + } + + @Override + public Action getAction() { + return action; + } + + @Override + public Date getCreatedAt() { + return createdAt; + } + + @Override + public long getMaxPosition() { + return maxPosition; + } + + @Override + public long getMinPosition() { + return minPosition; + } + + @Override + public User[] getSources() { + return sources; + } + + @Override + public int getSourcesSize() { + return sourcesSize; + } + + @Override + public int getTargetObjectsSize() { + return targetObjectsSize; + } + + @Override + public Status[] getTargetObjectStatuses() { + return targetObjectStatuses; + } + + @Override + public UserList[] getTargetObjectUserLists() { + return targetObjectUserLists; + } + + @Override + public int getTargetsSize() { + return targetsSize; + } + + @Override + public Status[] getTargetStatuses() { + return targetStatuses; + } + + @Override + public UserList[] getTargetUserLists() { + return targetUserLists; + } + + @Override + public User[] getTargetUsers() { + return targetUsers; + } + + @Override + public String toString() { + return "ActivityJSONImpl{" + + "action=" + action + + ", createdAt=" + createdAt + + ", sources=" + Arrays.toString(sources) + + ", targetUsers=" + Arrays.toString(targetUsers) + + ", targetObjectStatuses=" + Arrays.toString(targetObjectStatuses) + + ", targetStatuses=" + Arrays.toString(targetStatuses) + + ", targetUserLists=" + Arrays.toString(targetUserLists) + + ", targetObjectUserLists=" + Arrays.toString(targetObjectUserLists) + + ", maxPosition=" + maxPosition + + ", minPosition=" + minPosition + + ", targetObjectsSize=" + targetObjectsSize + + ", targetsSize=" + targetsSize + + ", sourcesSize=" + sourcesSize + + '}'; + } + + final void init(final JSONObject json) throws TwitterException { + try { + action = Action.fromString(getRawString("action", json)); + maxPosition = getLong("max_position", json); + minPosition = getLong("min_position", json); + createdAt = getDate("created_at", json, "EEE MMM dd HH:mm:ss z yyyy"); + sourcesSize = getInt("sources_size", json); + targetsSize = getInt("targets_size", json); + final JSONArray sources_array = json.getJSONArray("sources"); + final JSONArray targets_array = json.getJSONArray("targets"); + final int sources_size = sources_array.length(); + final int targets_size = targets_array.length(); + if (action == Action.LIST_CREATED) { + + } else if (action == Action.FOLLOW || action == Action.MENTION || action == Action.LIST_MEMBER_ADDED) { + targetUsers = new User[targets_size]; + for (int i = 0; i < targets_size; i++) { + targetUsers[i] = new UserJSONImpl(targets_array.getJSONObject(i)); + } + } else { + targetStatuses = new Status[targets_size]; + for (int i = 0; i < targets_size; i++) { + targetStatuses[i] = new StatusJSONImpl(targets_array.getJSONObject(i)); + } + } + sources = new User[sources_size]; + for (int i = 0; i < sources_size; i++) { + sources[i] = new UserJSONImpl(sources_array.getJSONObject(i)); + } + final JSONArray target_objects_array = json.getJSONArray("target_objects"); + final int target_objects_size = target_objects_array.length(); + if (action == Action.LIST_MEMBER_ADDED) { + targetObjectUserLists = new UserList[target_objects_size]; + for (int i = 0; i < target_objects_size; i++) { + targetObjectUserLists[i] = new UserListJSONImpl(target_objects_array.getJSONObject(i)); + } + } else if (action == Action.LIST_CREATED) { + targetUserLists = new UserList[targets_size]; + for (int i = 0; i < targets_size; i++) { + targetUserLists[i] = new UserListJSONImpl(targets_array.getJSONObject(i)); + } + } else { + targetObjectStatuses = new Status[target_objects_size]; + for (int i = 0; i < target_objects_size; i++) { + targetObjectStatuses[i] = new StatusJSONImpl(target_objects_array.getJSONObject(i)); + } + } + targetObjectsSize = getInt("target_objects_size", json); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + /* package */ + static ResponseList createActivityList(final HttpResponse res, final Configuration conf) + throws TwitterException { + return createActivityList(res.asJSONArray(), res, conf); + } + + /* package */ + static ResponseList createActivityList(final JSONArray list, final HttpResponse res, + final Configuration conf) throws TwitterException { + try { + final int size = list.length(); + final ResponseList users = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final Activity activity = new ActivityJSONImpl(json); + users.add(activity); + } + return users; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/CardEntityJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/CardEntityJSONImpl.java new file mode 100644 index 00000000..15a1caef --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/CardEntityJSONImpl.java @@ -0,0 +1,248 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import twitter4j.CardEntity; +import twitter4j.TwitterException; +import twitter4j.User; +import twitter4j.internal.util.InternalParseUtil; + +/** + * Created by mariotaku on 14/12/31. + */ +public class CardEntityJSONImpl implements CardEntity { + + private final String name; + private final Map bindingValues; + private final User[] users; + + public CardEntityJSONImpl(JSONObject json) throws JSONException, TwitterException { + this.name = json.getString("name"); + this.bindingValues = BindingValueImpl.valuesOf(json.getJSONObject("binding_values")); + if (!json.isNull("users")) { + final JSONObject usersJSON = json.getJSONObject("users"); + final Iterator keys = usersJSON.keys(); + this.users = new UserJSONImpl[usersJSON.length()]; + int idx = 0; + while (keys.hasNext()) { + users[idx++] = new UserJSONImpl(usersJSON.getJSONObject(keys.next())); + } + } else { + users = null; + } + } + + @Override + public String getName() { + return name; + } + + @Override + public User[] gerUsers() { + return users; + } + + @Override + public BindingValue getBindingValue(String name) { + return bindingValues.get(name); + } + + @Override + public BindingValue[] getBindingValues() { + return bindingValues.values().toArray(new BindingValue[bindingValues.size()]); + } + + + public static abstract class BindingValueImpl implements BindingValue { + protected final String name, type; + + BindingValueImpl(String name, JSONObject json) throws JSONException { + this.name = name; + this.type = json.getString("type"); + } + + @Override + public final String getName() { + return name; + } + + @Override + public final String getType() { + return type; + } + + private static BindingValue valueOf(String name, JSONObject json) throws JSONException, TwitterException { + final String type = json.getString("type"); + if (TYPE_STRING.equals(type)) { + return new StringValueImpl(name, json); + } else if (TYPE_IMAGE.equals(type)) { + return new ImageValueImpl(name, json); + } else if (TYPE_USER.equals(type)) { + return new UserValueImpl(name, json); + } else if (TYPE_BOOLEAN.equals(type)) { + return new BooleanValueImpl(name, json); + } + throw new TwitterException(String.format("Unsupported type %s", type)); + } + + private static HashMap valuesOf(JSONObject json) throws JSONException, TwitterException { + final Iterator keys = json.keys(); + final HashMap values = new HashMap<>(); + while (keys.hasNext()) { + final String key = keys.next(); + if (!json.isNull("name")) { + values.put(key, valueOf(key, json.getJSONObject(key))); + } + } + return values; + } + } + + private static final class ImageValueImpl extends BindingValueImpl implements ImageValue { + + private final int width, height; + private final String url; + + ImageValueImpl(String name, JSONObject json) throws JSONException { + super(name, json); + final JSONObject imageValue = json.getJSONObject("image_value"); + this.width = imageValue.getInt("width"); + this.height = imageValue.getInt("height"); + this.url = imageValue.getString("url"); + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public String getUrl() { + return url; + } + + @Override + public String toString() { + return "ImageValueImpl{" + + "name='" + name + '\'' + + "width=" + width + + ", height=" + height + + ", url='" + url + '\'' + + '}'; + } + } + + private static final class BooleanValueImpl extends BindingValueImpl implements BooleanValue { + + @Override + public String toString() { + return "BooleanValueImpl{" + + "value=" + value + + '}'; + } + + private final boolean value; + + BooleanValueImpl(String name, JSONObject json) throws JSONException { + super(name, json); + this.value = json.getBoolean("boolean_value"); + } + + @Override + public boolean getValue() { + return value; + } + + + } + + private static final class StringValueImpl extends BindingValueImpl implements StringValue { + + private final String value; + + StringValueImpl(String name, JSONObject json) throws JSONException { + super(name, json); + this.value = json.getString("string_value"); + } + + @Override + public String getValue() { + return value; + } + + @Override + public String toString() { + return "StringValueImpl{" + + "name='" + name + '\'' + + "value='" + value + '\'' + + '}'; + } + + + } + + private static final class UserValueImpl extends BindingValueImpl implements UserValue { + + private final long userId; + + UserValueImpl(String name, JSONObject json) throws JSONException { + super(name, json); + final JSONObject userValue = json.getJSONObject("user_value"); + this.userId = InternalParseUtil.getLong("id_str", userValue); + } + + @Override + public long getUserId() { + return userId; + } + + @Override + public String toString() { + return "UserValueImpl{" + + "name='" + name + '\'' + + "userId='" + userId + '\'' + + '}'; + } + + + } + + @Override + public String toString() { + return "CardEntityJSONImpl{" + + "name='" + name + '\'' + + ", bindingValues=" + bindingValues + + ", users=" + Arrays.toString(users) + + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/CategoryJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/CategoryJSONImpl.java new file mode 100644 index 00000000..e6bb67cd --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/CategoryJSONImpl.java @@ -0,0 +1,119 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.Category; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +final class CategoryJSONImpl implements Category { + + /** + * + */ + private static final long serialVersionUID = 2315575353091021075L; + private String name; + private String slug; + private int size; + + CategoryJSONImpl(final JSONObject json) throws JSONException { + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final CategoryJSONImpl that = (CategoryJSONImpl) o; + + if (size != that.size) return false; + if (name != null ? !name.equals(that.name) : that.name != null) return false; + if (slug != null ? !slug.equals(that.slug) : that.slug != null) return false; + + return true; + } + + @Override + public String getName() { + return name; + } + + /** + * @return + * @since Twitter4J 2.1.9 + */ + @Override + public int getSize() { + return size; + } + + @Override + public String getSlug() { + return slug; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (slug != null ? slug.hashCode() : 0); + result = 31 * result + size; + return result; + } + + @Override + public String toString() { + return "CategoryJSONImpl{" + "name='" + name + '\'' + ", slug='" + slug + '\'' + ", size=" + size + '}'; + } + + void init(final JSONObject json) throws JSONException { + name = json.getString("name"); + slug = json.getString("slug"); + size = InternalParseUtil.getInt("size", json); + } + + static ResponseList createCategoriesList(final HttpResponse res, final Configuration conf) + throws TwitterException { + return createCategoriesList(res.asJSONArray(), res, conf); + } + + static ResponseList createCategoriesList(final JSONArray array, final HttpResponse res, + final Configuration conf) throws TwitterException { + try { + final ResponseList categories = new ResponseListImpl(array.length(), res); + for (int i = 0; i < array.length(); i++) { + final JSONObject json = array.getJSONObject(i); + final Category category = new CategoryJSONImpl(json); + categories.add(category); + } + return categories; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/DirectMessageJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/DirectMessageJSONImpl.java new file mode 100644 index 00000000..d20000fc --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/DirectMessageJSONImpl.java @@ -0,0 +1,289 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.Date; + +import twitter4j.DirectMessage; +import twitter4j.HashtagEntity; +import twitter4j.MediaEntity; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.URLEntity; +import twitter4j.User; +import twitter4j.UserMentionEntity; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getDate; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; +import static twitter4j.internal.util.InternalParseUtil.getUnescapedString; + +/** + * A data class representing sent/received direct message. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +/* package */final class DirectMessageJSONImpl extends TwitterResponseImpl implements DirectMessage { + + /** + * + */ + private static final long serialVersionUID = 8809144846145143089L; + private long id; + private String text; + private String rawText; + private long senderId; + private long recipientId; + private Date createdAt; + private String senderScreenName; + private String recipientScreenName; + + private UserMentionEntity[] userMentionEntities; + private URLEntity[] urlEntities; + private HashtagEntity[] hashtagEntities; + private MediaEntity[] mediaEntities; + + private User sender; + + private User recipient; + + /* package */DirectMessageJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */DirectMessageJSONImpl(final JSONObject json) throws TwitterException { + init(json); + } + + @Override + public boolean equals(final Object obj) { + if (null == obj) return false; + if (this == obj) return true; + return obj instanceof DirectMessage && ((DirectMessage) obj).getId() == id; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getCreatedAt() { + return createdAt; + } + + @Override + public HashtagEntity[] getHashtagEntities() { + return hashtagEntities; + } + + /** + * {@inheritDoc} + */ + @Override + public long getId() { + return id; + } + + @Override + public MediaEntity[] getMediaEntities() { + return mediaEntities; + } + + @Override + public String getRawText() { + return rawText; + } + + /** + * {@inheritDoc} + */ + @Override + public User getRecipient() { + return recipient; + } + + /** + * {@inheritDoc} + */ + @Override + public long getRecipientId() { + return recipientId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getRecipientScreenName() { + return recipientScreenName; + } + + /** + * {@inheritDoc} + */ + @Override + public User getSender() { + return sender; + } + + /** + * {@inheritDoc} + */ + @Override + public long getSenderId() { + return senderId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getSenderScreenName() { + return senderScreenName; + } + + /** + * {@inheritDoc} + */ + @Override + public String getText() { + return text; + } + + @Override + public URLEntity[] getURLEntities() { + return urlEntities; + } + + @Override + public UserMentionEntity[] getUserMentionEntities() { + return userMentionEntities; + } + + @Override + public int hashCode() { + return (int) id; + } + + @Override + public String toString() { + return "DirectMessageJSONImpl{" + + "id=" + id + + ", text='" + text + '\'' + + ", rawText='" + rawText + '\'' + + ", senderId=" + senderId + + ", recipientId=" + recipientId + + ", createdAt=" + createdAt + + ", senderScreenName='" + senderScreenName + '\'' + + ", recipientScreenName='" + recipientScreenName + '\'' + + ", userMentionEntities=" + Arrays.toString(userMentionEntities) + + ", urlEntities=" + Arrays.toString(urlEntities) + + ", hashtagEntities=" + Arrays.toString(hashtagEntities) + + ", mediaEntities=" + Arrays.toString(mediaEntities) + + ", sender=" + sender + + ", recipient=" + recipient + + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + id = getLong("id", json); + text = getUnescapedString("text", json); + rawText = getRawString("text", json); + senderId = getLong("sender_id", json); + recipientId = getLong("recipient_id", json); + createdAt = getDate("created_at", json); + senderScreenName = getRawString("sender_screen_name", json); + recipientScreenName = getRawString("recipient_screen_name", json); + if (!json.isNull("entities")) { + try { + final JSONObject entities = json.getJSONObject("entities"); + int len; + if (!entities.isNull("user_mentions")) { + final JSONArray userMentionsArray = entities.getJSONArray("user_mentions"); + len = userMentionsArray.length(); + userMentionEntities = new UserMentionEntity[len]; + for (int i = 0; i < len; i++) { + userMentionEntities[i] = new UserMentionEntityJSONImpl(userMentionsArray.getJSONObject(i)); + } + } + if (!entities.isNull("urls")) { + final JSONArray urlsArray = entities.getJSONArray("urls"); + len = urlsArray.length(); + urlEntities = new URLEntity[len]; + for (int i = 0; i < len; i++) { + urlEntities[i] = new URLEntityJSONImpl(urlsArray.getJSONObject(i)); + } + } + if (!entities.isNull("hashtags")) { + final JSONArray hashtagsArray = entities.getJSONArray("hashtags"); + len = hashtagsArray.length(); + hashtagEntities = new HashtagEntity[len]; + for (int i = 0; i < len; i++) { + hashtagEntities[i] = new HashtagEntityJSONImpl(hashtagsArray.getJSONObject(i)); + } + } + if (!entities.isNull("media")) { + final JSONArray mediaArray = entities.getJSONArray("media"); + len = mediaArray.length(); + mediaEntities = new MediaEntity[len]; + for (int i = 0; i < len; i++) { + mediaEntities[i] = new MediaEntityJSONImpl(mediaArray.getJSONObject(i)); + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + try { + sender = new UserJSONImpl(json.getJSONObject("sender")); + recipient = new UserJSONImpl(json.getJSONObject("recipient")); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + /* package */ + static ResponseList createDirectMessageList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONArray list = res.asJSONArray(); + final int size = list.length(); + final ResponseList directMessages = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final DirectMessage directMessage = new DirectMessageJSONImpl(json); + directMessages.add(directMessage); + } + return directMessages; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/FriendshipJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/FriendshipJSONImpl.java new file mode 100644 index 00000000..9bd71723 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/FriendshipJSONImpl.java @@ -0,0 +1,142 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.Friendship; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getLong; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +class FriendshipJSONImpl implements Friendship { + + private final long id; + private final String name; + private final String screenName; + private boolean following = false; + private boolean followedBy = false; + + /* package */FriendshipJSONImpl(final JSONObject json) throws TwitterException { + super(); + try { + id = getLong("id", json); + name = json.getString("name"); + screenName = json.getString("screen_name"); + final JSONArray connections = json.getJSONArray("connections"); + for (int i = 0; i < connections.length(); i++) { + final String connection = connections.getString(i); + if ("following".equals(connection)) { + following = true; + } else if ("followed_by".equals(connection)) { + followedBy = true; + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final FriendshipJSONImpl that = (FriendshipJSONImpl) o; + + if (followedBy != that.followedBy) return false; + if (following != that.following) return false; + if (id != that.id) return false; + if (!name.equals(that.name)) return false; + if (!screenName.equals(that.screenName)) return false; + + return true; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getScreenName() { + return screenName; + } + + @Override + public int hashCode() { + int result = (int) (id ^ id >>> 32); + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (screenName != null ? screenName.hashCode() : 0); + result = 31 * result + (following ? 1 : 0); + result = 31 * result + (followedBy ? 1 : 0); + return result; + } + + @Override + public boolean isFollowedBy() { + return followedBy; + } + + @Override + public boolean isFollowing() { + return following; + } + + @Override + public String toString() { + return "FriendshipJSONImpl{" + "id=" + id + ", name='" + name + '\'' + ", screenName='" + screenName + '\'' + + ", following=" + following + ", followedBy=" + followedBy + '}'; + } + + /* package */ + static ResponseList createFriendshipList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONArray list = res.asJSONArray(); + final int size = list.length(); + final ResponseList friendshipList = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final Friendship friendship = new FriendshipJSONImpl(json); + friendshipList.add(friendship); + } + return friendshipList; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/HashtagEntityJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/HashtagEntityJSONImpl.java new file mode 100644 index 00000000..42f83d9f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/HashtagEntityJSONImpl.java @@ -0,0 +1,123 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.HashtagEntity; +import twitter4j.TwitterException; + +/** + * A data class representing one single Hashtag entity. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +/* package */class HashtagEntityJSONImpl implements HashtagEntity { + + /** + * + */ + private static final long serialVersionUID = 2514471410110223225L; + private int start = -1; + private int end = -1; + private String text; + + /* For serialization purposes only. */ + /* package */HashtagEntityJSONImpl() { + + } + + /* package */HashtagEntityJSONImpl(final int start, final int end, final String text) { + super(); + this.start = start; + this.end = end; + this.text = text; + } + + /* package */HashtagEntityJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final HashtagEntityJSONImpl that = (HashtagEntityJSONImpl) o; + + if (end != that.end) return false; + if (start != that.start) return false; + if (text != null ? !text.equals(that.text) : that.text != null) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int getEnd() { + return end; + } + + /** + * {@inheritDoc} + */ + @Override + public int getStart() { + return start; + } + + /** + * {@inheritDoc} + */ + @Override + public String getText() { + return text; + } + + @Override + public int hashCode() { + int result = start; + result = 31 * result + end; + result = 31 * result + (text != null ? text.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "HashtagEntityJSONImpl{" + "start=" + start + ", end=" + end + ", text='" + text + '\'' + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + final JSONArray indicesArray = json.getJSONArray("indices"); + start = indicesArray.getInt(0); + end = indicesArray.getInt(1); + + if (!json.isNull("text")) { + text = json.getString("text"); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/IDsJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/IDsJSONImpl.java new file mode 100644 index 00000000..d8730840 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/IDsJSONImpl.java @@ -0,0 +1,152 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; + +import twitter4j.IDs; +import twitter4j.TwitterException; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; + +/** + * A data class representing array of numeric IDs. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +/* package */final class IDsJSONImpl extends TwitterResponseImpl implements IDs { + + /** + * + */ + private static final long serialVersionUID = 443834529674409001L; + private long[] ids; + private long previousCursor = -1; + private long nextCursor = -1; + + /* package */IDsJSONImpl(final HttpResponse res) throws TwitterException { + super(res); + final String json = res.asString(); + init(json); + } + + /* package */IDsJSONImpl(final String json) throws TwitterException { + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof IDs)) return false; + + final IDs iDs = (IDs) o; + + if (!Arrays.equals(ids, iDs.getIDs())) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public long[] getIDs() { + return ids; + } + + /** + * {@inheritDoc} + */ + @Override + public long getNextCursor() { + return nextCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public long getPreviousCursor() { + return previousCursor; + } + + @Override + public int hashCode() { + return ids != null ? Arrays.hashCode(ids) : 0; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasNext() { + return 0 != nextCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasPrevious() { + return 0 != previousCursor; + } + + @Override + public String toString() { + return "IDsJSONImpl{" + "ids=" + Arrays.toString(ids) + ", previousCursor=" + previousCursor + ", nextCursor=" + + nextCursor + '}'; + } + + private void init(final String jsonStr) throws TwitterException { + JSONArray idList; + try { + if (jsonStr.startsWith("{")) { + final JSONObject json = new JSONObject(jsonStr); + idList = json.getJSONArray("ids"); + ids = new long[idList.length()]; + for (int i = 0; i < idList.length(); i++) { + try { + ids[i] = Long.parseLong(idList.getString(i)); + } catch (final NumberFormatException nfe) { + throw new TwitterException("Twitter API returned malformed response: " + json, nfe); + } + } + previousCursor = InternalParseUtil.getLong("previous_cursor", json); + nextCursor = InternalParseUtil.getLong("next_cursor", json); + } else { + idList = new JSONArray(jsonStr); + ids = new long[idList.length()]; + for (int i = 0; i < idList.length(); i++) { + try { + ids[i] = Long.parseLong(idList.getString(i)); + } catch (final NumberFormatException nfe) { + throw new TwitterException("Twitter API returned malformed response: " + idList, nfe); + } + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/InternalJSONFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/InternalJSONFactory.java new file mode 100644 index 00000000..6ea0c74c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/InternalJSONFactory.java @@ -0,0 +1,140 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONObject; + +import java.util.Map; + +import twitter4j.AccountSettings; +import twitter4j.AccountTotals; +import twitter4j.Activity; +import twitter4j.Category; +import twitter4j.DirectMessage; +import twitter4j.Friendship; +import twitter4j.IDs; +import twitter4j.Location; +import twitter4j.MediaUploadResponse; +import twitter4j.OEmbed; +import twitter4j.PageableResponseList; +import twitter4j.Place; +import twitter4j.Query; +import twitter4j.QueryResult; +import twitter4j.RateLimitStatus; +import twitter4j.Relationship; +import twitter4j.ResponseList; +import twitter4j.SavedSearch; +import twitter4j.SimilarPlaces; +import twitter4j.Status; +import twitter4j.StatusActivitySummary; +import twitter4j.TranslationResult; +import twitter4j.Trends; +import twitter4j.TwitterAPIConfiguration; +import twitter4j.TwitterException; +import twitter4j.User; +import twitter4j.UserList; +import twitter4j.api.HelpResources; +import twitter4j.http.HttpResponse; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.4 + */ +public interface InternalJSONFactory { + AccountSettings createAccountSettings(HttpResponse res) throws TwitterException; + + AccountTotals createAccountTotals(HttpResponse res) throws TwitterException; + + ResponseList createActivityList(HttpResponse res) throws TwitterException; + + UserList createAUserList(HttpResponse res) throws TwitterException; + + UserList createAUserList(JSONObject json) throws TwitterException; + + ResponseList createCategoryList(HttpResponse res) throws TwitterException; + + DirectMessage createDirectMessage(HttpResponse res) throws TwitterException; + + DirectMessage createDirectMessage(JSONObject json) throws TwitterException; + + ResponseList createDirectMessageList(HttpResponse res) throws TwitterException; + + ResponseList createEmptyResponseList(); + + ResponseList createFriendshipList(HttpResponse res) throws TwitterException; + + IDs createIDs(HttpResponse res) throws TwitterException; + + ResponseList createLanguageList(HttpResponse res) throws TwitterException; + + ResponseList createLocationList(HttpResponse res) throws TwitterException; + + MediaUploadResponse createMediaUploadResponse(HttpResponse res) throws TwitterException; + + OEmbed createOEmbed(HttpResponse httpResponse) throws TwitterException; + + PageableResponseList createPagableUserList(HttpResponse res) throws TwitterException; + + PageableResponseList createPagableUserListList(HttpResponse res) throws TwitterException; + + Place createPlace(HttpResponse res) throws TwitterException; + + ResponseList createPlaceList(HttpResponse res) throws TwitterException; + + QueryResult createQueryResult(HttpResponse res, Query query) throws TwitterException; + + Map createRateLimitStatus(HttpResponse res) throws TwitterException; + + Relationship createRelationship(HttpResponse res) throws TwitterException; + + SavedSearch createSavedSearch(HttpResponse res) throws TwitterException; + + ResponseList createSavedSearchList(HttpResponse res) throws TwitterException; + + SimilarPlaces createSimilarPlaces(HttpResponse res) throws TwitterException; + + Status createStatus(HttpResponse res) throws TwitterException; + + Status createStatus(JSONObject json) throws TwitterException; + + StatusActivitySummary createStatusActivitySummary(HttpResponse res) throws TwitterException; + + ResponseList createStatusList(HttpResponse res) throws TwitterException; + + TranslationResult createTranslationResult(HttpResponse res) throws TwitterException; + + Trends createTrends(HttpResponse res) throws TwitterException; + + ResponseList createTrendsList(HttpResponse res) throws TwitterException; + + TwitterAPIConfiguration createTwitterAPIConfiguration(HttpResponse res) throws TwitterException; + + User createUser(HttpResponse res) throws TwitterException; + + User createUser(JSONObject json) throws TwitterException; + + ResponseList createUserList(HttpResponse res) throws TwitterException; + + ResponseList createUserListFromJSONArray(HttpResponse res) throws TwitterException; + + ResponseList createUserListFromJSONArray_Users(HttpResponse res) throws TwitterException; + + ResponseList createUserListList(HttpResponse res) throws TwitterException; +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/InternalJSONFactoryImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/InternalJSONFactoryImpl.java new file mode 100644 index 00000000..4aa1de52 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/InternalJSONFactoryImpl.java @@ -0,0 +1,392 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Map; + +import twitter4j.AccountSettings; +import twitter4j.AccountTotals; +import twitter4j.Activity; +import twitter4j.Category; +import twitter4j.DirectMessage; +import twitter4j.Friendship; +import twitter4j.GeoLocation; +import twitter4j.HashtagEntity; +import twitter4j.IDs; +import twitter4j.Location; +import twitter4j.MediaUploadResponse; +import twitter4j.OEmbed; +import twitter4j.PageableResponseList; +import twitter4j.Place; +import twitter4j.Query; +import twitter4j.QueryResult; +import twitter4j.RateLimitStatus; +import twitter4j.Relationship; +import twitter4j.ResponseList; +import twitter4j.SavedSearch; +import twitter4j.SimilarPlaces; +import twitter4j.Status; +import twitter4j.StatusActivitySummary; +import twitter4j.TranslationResult; +import twitter4j.Trends; +import twitter4j.TwitterAPIConfiguration; +import twitter4j.TwitterException; +import twitter4j.URLEntity; +import twitter4j.User; +import twitter4j.UserList; +import twitter4j.UserMentionEntity; +import twitter4j.api.HelpResources; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalStringUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.4 + */ +public class InternalJSONFactoryImpl implements InternalJSONFactory { + + private final Configuration conf; + + public InternalJSONFactoryImpl(final Configuration conf) { + this.conf = conf; + } + + @Override + public AccountSettings createAccountSettings(final HttpResponse res) throws TwitterException { + return new AccountSettingsJSONImpl(res, conf); + } + + @Override + public AccountTotals createAccountTotals(final HttpResponse res) throws TwitterException { + return new AccountTotalsJSONImpl(res, conf); + } + + @Override + public ResponseList createActivityList(final HttpResponse res) throws TwitterException { + return ActivityJSONImpl.createActivityList(res, conf); + } + + @Override + public UserList createAUserList(final HttpResponse res) throws TwitterException { + return new UserListJSONImpl(res, conf); + } + + @Override + public UserList createAUserList(final JSONObject json) throws TwitterException { + return new UserListJSONImpl(json); + } + + @Override + public ResponseList createCategoryList(final HttpResponse res) throws TwitterException { + return CategoryJSONImpl.createCategoriesList(res, conf); + } + + @Override + public DirectMessage createDirectMessage(final HttpResponse res) throws TwitterException { + return new DirectMessageJSONImpl(res, conf); + } + + @Override + public DirectMessage createDirectMessage(final JSONObject json) throws TwitterException { + return new DirectMessageJSONImpl(json); + } + + @Override + public ResponseList createDirectMessageList(final HttpResponse res) throws TwitterException { + return DirectMessageJSONImpl.createDirectMessageList(res, conf); + } + + @Override + public ResponseList createEmptyResponseList() { + return new ResponseListImpl<>(0, null); + } + + @Override + public ResponseList createFriendshipList(final HttpResponse res) throws TwitterException { + return FriendshipJSONImpl.createFriendshipList(res, conf); + } + + @Override + public IDs createIDs(final HttpResponse res) throws TwitterException { + return new IDsJSONImpl(res); + } + + @Override + public ResponseList createLanguageList(final HttpResponse res) throws TwitterException { + return LanguageJSONImpl.createLanguageList(res, conf); + } + + @Override + public ResponseList createLocationList(final HttpResponse res) throws TwitterException { + return LocationJSONImpl.createLocationList(res, conf); + } + + @Override + public MediaUploadResponse createMediaUploadResponse(final HttpResponse res) throws TwitterException { + return new MediaUploadResponseJSONImpl(res); + } + + @Override + public OEmbed createOEmbed(final HttpResponse res) throws TwitterException { + return new OEmbedJSONImpl(res, conf); + } + + @Override + public PageableResponseList createPagableUserList(final HttpResponse res) throws TwitterException { + return UserJSONImpl.createPagableUserList(res, conf); + } + + @Override + public PageableResponseList createPagableUserListList(final HttpResponse res) throws TwitterException { + return UserListJSONImpl.createPagableUserListList(res, conf); + } + + @Override + public Place createPlace(final HttpResponse res) throws TwitterException { + return new PlaceJSONImpl(res, conf); + } + + @Override + public ResponseList createPlaceList(final HttpResponse res) throws TwitterException { + try { + return PlaceJSONImpl.createPlaceList(res, conf); + } catch (final TwitterException te) { + if (te.getStatusCode() == 404) + return new ResponseListImpl<>(0, null); + else + throw te; + } + } + + @Override + public QueryResult createQueryResult(final HttpResponse res, final Query query) throws TwitterException { + try { + return new QueryResultJSONImpl(res); + } catch (final TwitterException te) { + if (404 == te.getStatusCode()) + return new QueryResultJSONImpl(res, query); + else + throw te; + } + } + + @Override + public Map createRateLimitStatus(final HttpResponse res) throws TwitterException { + return RateLimitStatusJSONImpl.createRateLimitStatuses(res, conf); + } + + @Override + public Relationship createRelationship(final HttpResponse res) throws TwitterException { + return new RelationshipJSONImpl(res, conf); + } + + @Override + public SavedSearch createSavedSearch(final HttpResponse res) throws TwitterException { + return new SavedSearchJSONImpl(res, conf); + } + + @Override + public ResponseList createSavedSearchList(final HttpResponse res) throws TwitterException { + return SavedSearchJSONImpl.createSavedSearchList(res, conf); + } + + @Override + public SimilarPlaces createSimilarPlaces(final HttpResponse res) throws TwitterException { + return SimilarPlacesImpl.createSimilarPlaces(res, conf); + } + + @Override + public Status createStatus(final HttpResponse res) throws TwitterException { + return new StatusJSONImpl(res, conf); + } + + @Override + public Status createStatus(final JSONObject json) throws TwitterException { + return new StatusJSONImpl(json); + } + + @Override + public StatusActivitySummary createStatusActivitySummary(final HttpResponse res) throws TwitterException { + return new StatusActivitySummaryJSONImpl(res, conf); + } + + @Override + public ResponseList createStatusList(final HttpResponse res) throws TwitterException { + return StatusJSONImpl.createStatusList(res, conf); + } + + @Override + public TranslationResult createTranslationResult(final HttpResponse res) throws TwitterException { + return new TranslationResultJSONImpl(res, conf); + } + + @Override + public Trends createTrends(final HttpResponse res) throws TwitterException { + return new TrendsJSONImpl(res, conf); + } + + @Override + public ResponseList createTrendsList(final HttpResponse res) throws TwitterException { + return TrendsJSONImpl.createTrendsList(res, false); + } + + @Override + public TwitterAPIConfiguration createTwitterAPIConfiguration(final HttpResponse res) throws TwitterException { + return new TwitterAPIConfigurationJSONImpl(res, conf); + } + + @Override + public User createUser(final HttpResponse res) throws TwitterException { + return new UserJSONImpl(res, conf); + } + + @Override + public User createUser(final JSONObject json) throws TwitterException { + return new UserJSONImpl(json); + } + + @Override + public ResponseList createUserList(final HttpResponse res) throws TwitterException { + return UserJSONImpl.createUserList(res, conf); + } + + @Override + public ResponseList createUserListFromJSONArray(final HttpResponse res) throws TwitterException { + return UserJSONImpl.createUserList(res.asJSONArray(), res, conf); + } + + @Override + public ResponseList createUserListFromJSONArray_Users(final HttpResponse res) throws TwitterException { + try { + return UserJSONImpl.createUserList(res.asJSONObject().getJSONArray("users"), res, conf); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + @Override + public ResponseList createUserListList(final HttpResponse res) throws TwitterException { + return UserListJSONImpl.createUserListList(res, conf); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof InternalJSONFactoryImpl)) return false; + + final InternalJSONFactoryImpl that = (InternalJSONFactoryImpl) o; + + if (conf != null ? !conf.equals(that.conf) : that.conf != null) return false; + + return true; + } + + @Override + public int hashCode() { + return conf != null ? conf.hashCode() : 0; + } + + @Override + public String toString() { + return "JSONImplFactory{" + "conf=" + conf + '}'; + } + + /** + * static factory method for twitter-text-java + * + * @return hashtag entity + * @since Twitter4J 2.2.6 + */ + public static HashtagEntity createHashtagEntity(final int start, final int end, final String text) { + return new HashtagEntityJSONImpl(start, end, text); + } + + public static RateLimitStatus createRateLimitStatusFromResponseHeader(final HttpResponse res) { + return RateLimitStatusJSONImpl.createFromResponseHeader(res); + } + + /** + * static factory method for twitter-text-java + * + * @return url entity + * @since Twitter4J 2.2.6 + */ + public static URLEntity createUrlEntity(final int start, final int end, final String url, final String expandedURL, + final String displayURL) { + return new URLEntityJSONImpl(start, end, url, expandedURL, displayURL); + } + + /** + * static factory method for twitter-text-java + * + * @return user mention entity + * @since Twitter4J 2.2.6 + */ + public static UserMentionEntity createUserMentionEntity(final int start, final int end, final String name, + final String screenName, final long id) { + return new UserMentionEntityJSONImpl(start, end, name, screenName, id); + } + + /* package */ + static GeoLocation[][] coordinatesAsGeoLocationArray(final JSONArray coordinates) throws TwitterException { + try { + final GeoLocation[][] boundingBox = new GeoLocation[coordinates.length()][]; + for (int i = 0; i < coordinates.length(); i++) { + final JSONArray array = coordinates.getJSONArray(i); + boundingBox[i] = new GeoLocation[array.length()]; + for (int j = 0; j < array.length(); j++) { + final JSONArray coordinate = array.getJSONArray(j); + boundingBox[i][j] = new GeoLocation(coordinate.getDouble(1), coordinate.getDouble(0)); + } + } + return boundingBox; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + /** + * returns a GeoLocation instance if a "geo" element is found. + * + * @param json JSONObject to be parsed + * @return GeoLocation instance + * @throws TwitterException when coordinates is not included in geo element + * (should be an API side issue) + */ + /* package */ + static GeoLocation createGeoLocation(final JSONObject json) throws TwitterException { + try { + if (!json.isNull("geo")) { + String coordinates = json.getJSONObject("geo").getString("coordinates"); + coordinates = coordinates.substring(1, coordinates.length() - 1); + final String[] point = InternalStringUtil.split(coordinates, ","); + return new GeoLocation(Double.parseDouble(point[0]), Double.parseDouble(point[1])); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + return null; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/LanguageJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/LanguageJSONImpl.java new file mode 100644 index 00000000..a58f6cdb --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/LanguageJSONImpl.java @@ -0,0 +1,93 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.api.HelpResources; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.3 + */ +public class LanguageJSONImpl implements HelpResources.Language { + private String name; + private String code; + private String status; + + LanguageJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getStatus() { + return status; + } + + private void init(final JSONObject json) throws TwitterException { + try { + name = json.getString("name"); + code = json.getString("code"); + status = json.getString("status"); + + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + static ResponseList createLanguageList(final HttpResponse res, final Configuration conf) + throws TwitterException { + return createLanguageList(res.asJSONArray(), res, conf); + } + + /* package */ + static ResponseList createLanguageList(final JSONArray list, final HttpResponse res, + final Configuration conf) throws TwitterException { + try { + final int size = list.length(); + final ResponseList languages = new ResponseListImpl(size, + res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final HelpResources.Language language = new LanguageJSONImpl(json); + languages.add(language); + } + return languages; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/LocationJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/LocationJSONImpl.java new file mode 100644 index 00000000..75fbcd2b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/LocationJSONImpl.java @@ -0,0 +1,171 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.Location; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + */ +/* package */final class LocationJSONImpl implements Location { + private final int woeid; + private final String countryName; + private final String countryCode; + private final String placeName; + private final int placeCode; + private final String name; + private final String url; + + /* package */LocationJSONImpl(final JSONObject location) throws TwitterException { + try { + woeid = getInt("woeid", location); + countryName = getHTMLUnescapedString("country", location); + countryCode = getRawString("countryCode", location); + if (!location.isNull("placeType")) { + final JSONObject placeJSON = location.getJSONObject("placeType"); + placeName = getHTMLUnescapedString("name", placeJSON); + placeCode = getInt("code", placeJSON); + } else { + placeName = null; + placeCode = -1; + } + name = getHTMLUnescapedString("name", location); + url = getHTMLUnescapedString("url", location); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof LocationJSONImpl)) return false; + + final LocationJSONImpl that = (LocationJSONImpl) o; + + if (woeid != that.woeid) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCountryCode() { + return countryCode; + } + + /** + * {@inheritDoc} + */ + @Override + public String getCountryName() { + return countryName; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public int getPlaceCode() { + return placeCode; + } + + /** + * {@inheritDoc} + */ + @Override + public String getPlaceName() { + return placeName; + } + + /** + * {@inheritDoc} + */ + @Override + public String getURL() { + return url; + } + + /** + * {@inheritDoc} + */ + @Override + public int getWoeid() { + return woeid; + } + + @Override + public int hashCode() { + return woeid; + } + + @Override + public String toString() { + return "LocationJSONImpl{" + "woeid=" + woeid + ", countryName='" + countryName + '\'' + ", countryCode='" + + countryCode + '\'' + ", placeName='" + placeName + '\'' + ", placeCode='" + placeCode + '\'' + + ", name='" + name + '\'' + ", url='" + url + '\'' + '}'; + } + + /* package */ + static ResponseList createLocationList(final HttpResponse res, final Configuration conf) + throws TwitterException { + return createLocationList(res.asJSONArray()); + } + + /* package */ + static ResponseList createLocationList(final JSONArray list) throws TwitterException { + try { + final int size = list.length(); + final ResponseList locations = new ResponseListImpl(size, null); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final Location location = new LocationJSONImpl(json); + locations.add(location); + } + return locations; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/MediaEntityJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/MediaEntityJSONImpl.java new file mode 100644 index 00000000..22151e12 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/MediaEntityJSONImpl.java @@ -0,0 +1,354 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import twitter4j.MediaEntity; +import twitter4j.TwitterException; + +import static twitter4j.internal.util.InternalParseUtil.getLong; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.3 + */ +public class MediaEntityJSONImpl implements MediaEntity { + + /** + * + */ + private static final long serialVersionUID = -1634113112942821363L; + private long id; + private int start = -1; + private int end = -1; + private String url; + private String mediaURL; + private String mediaURLHttps; + private String expandedURL; + private String displayURL; + private Map sizes; + private Type type; + private VideoInfoJSONImpl videoInfo; + + public VideoInfo getVideoInfo() { + return videoInfo; + } + + public MediaEntityJSONImpl(final JSONObject json) throws TwitterException { + try { + final JSONArray indicesArray = json.getJSONArray("indices"); + start = indicesArray.getInt(0); + end = indicesArray.getInt(1); + id = getLong("id", json); + + url = (json.getString("url")); + + if (!json.isNull("expanded_url")) { + expandedURL = json.getString("expanded_url"); + } + if (!json.isNull("media_url")) { + mediaURL = (json.getString("media_url")); + } + if (!json.isNull("media_url_https")) { + mediaURLHttps = (json.getString("media_url_https")); + } + if (!json.isNull("display_url")) { + displayURL = json.getString("display_url"); + } + if (!json.isNull("video_info")) { + videoInfo = new VideoInfoJSONImpl(json.getJSONObject("video_info")); + } + final JSONObject sizes = json.getJSONObject("sizes"); + this.sizes = new HashMap(4); + // thumbworkarounding API side issue + addMediaEntitySizeIfNotNull(this.sizes, sizes, MediaEntity.Size.LARGE, "large"); + addMediaEntitySizeIfNotNull(this.sizes, sizes, MediaEntity.Size.MEDIUM, "medium"); + addMediaEntitySizeIfNotNull(this.sizes, sizes, MediaEntity.Size.SMALL, "small"); + addMediaEntitySizeIfNotNull(this.sizes, sizes, MediaEntity.Size.THUMB, "thumb"); + if (!json.isNull("type")) { + type = Type.parse(json.getString("type")); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + /* For serialization purposes only. */ + /* package */MediaEntityJSONImpl() { + + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof MediaEntityJSONImpl)) return false; + + final MediaEntityJSONImpl that = (MediaEntityJSONImpl) o; + + if (id != that.id) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String getDisplayURL() { + return displayURL; + } + + /** + * {@inheritDoc} + */ + @Override + public int getEnd() { + return end; + } + + /** + * {@inheritDoc} + */ + @Override + public String getExpandedURL() { + return expandedURL; + } + + /** + * {@inheritDoc} + */ + @Override + public long getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getMediaURL() { + return mediaURL; + } + + /** + * {@inheritDoc} + */ + @Override + public String getMediaURLHttps() { + return mediaURLHttps; + } + + @Override + public Map getSizes() { + return sizes; + } + + /** + * {@inheritDoc} + */ + @Override + public int getStart() { + return start; + } + + /** + * {@inheritDoc} + */ + @Override + public Type getType() { + return type; + } + + /** + * {@inheritDoc} + */ + @Override + public String getURL() { + return url; + } + + @Override + public int hashCode() { + return (int) (id ^ id >>> 32); + } + + @Override + public String toString() { + return "MediaEntityJSONImpl{" + "id=" + id + ", start=" + start + ", end=" + end + ", url=" + url + + ", mediaURL=" + mediaURL + ", mediaURLHttps=" + mediaURLHttps + ", expandedURL=" + expandedURL + + ", displayURL='" + displayURL + '\'' + ", sizes=" + sizes + ", type=" + type + '}'; + } + + private void addMediaEntitySizeIfNotNull(final Map sizes, final JSONObject sizes_json, + final Integer size, final String key) throws JSONException { + final JSONObject size_json = sizes_json.optJSONObject(key); + if (size_json != null) { + sizes.put(size, new Size(size_json)); + } + } + + static class Size implements MediaEntity.Size { + + /** + * + */ + private static final long serialVersionUID = 5638836742331957957L; + int width; + int height; + int resize; + + Size(final JSONObject json) throws JSONException { + width = json.getInt("w"); + height = json.getInt("h"); + resize = "fit".equals(json.getString("resize")) ? MediaEntity.Size.FIT : MediaEntity.Size.CROP; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Size)) return false; + + final Size size = (Size) o; + + if (height != size.height) return false; + if (resize != size.resize) return false; + if (width != size.width) return false; + + return true; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getResize() { + return resize; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int hashCode() { + int result = width; + result = 31 * result + height; + result = 31 * result + resize; + return result; + } + + @Override + public String toString() { + return "Size{" + "width=" + width + ", height=" + height + ", resize=" + resize + '}'; + } + } + + private static class VideoInfoJSONImpl implements VideoInfo { + + private final VariantJSONImpl[] variants; + private final long[] aspectRatio; + private final long duration; + + VideoInfoJSONImpl(JSONObject json) throws JSONException { + variants = VariantJSONImpl.fromJSONArray(json.getJSONArray("variants")); + final JSONArray aspectRatioJson = json.getJSONArray("aspect_ratio"); + aspectRatio = new long[]{aspectRatioJson.getLong(0), aspectRatioJson.getLong(1)}; + duration = json.optLong("duration_millis", -1); + } + + @Override + public Variant[] getVariants() { + return variants; + } + + @Override + public long[] getAspectRatio() { + return aspectRatio; + } + + @Override + public String toString() { + return "VideoInfoJSONImpl{" + + "variants=" + Arrays.toString(variants) + + ", aspectRatio=" + Arrays.toString(aspectRatio) + + ", duration=" + duration + + '}'; + } + + @Override + public long getDuration() { + return duration; + } + + private static class VariantJSONImpl implements Variant { + private final String contentType; + private final String url; + private final long bitrate; + + @Override + public String toString() { + return "VariantJSONImpl{" + + "contentType='" + contentType + '\'' + + ", url='" + url + '\'' + + ", bitrate=" + bitrate + + '}'; + } + + public VariantJSONImpl(JSONObject json) throws JSONException { + contentType = json.getString("content_type"); + url = json.getString("url"); + bitrate = json.optLong("bitrate", -1); + } + + public static VariantJSONImpl[] fromJSONArray(JSONArray json) throws JSONException { + final VariantJSONImpl[] variant = new VariantJSONImpl[json.length()]; + for (int i = 0, j = variant.length; i < j; i++) { + variant[i] = new VariantJSONImpl(json.getJSONObject(i)); + } + return variant; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public String getUrl() { + return url; + } + + @Override + public long getBitrate() { + return bitrate; + } + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/MediaUploadResponseJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/MediaUploadResponseJSONImpl.java new file mode 100644 index 00000000..a4524110 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/MediaUploadResponseJSONImpl.java @@ -0,0 +1,130 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.MediaUploadResponse; +import twitter4j.TwitterException; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +final class MediaUploadResponseJSONImpl extends TwitterResponseImpl implements MediaUploadResponse { + + private static final long serialVersionUID = 1024124737076048737L; + + private long id; + private long size; + + private ImageJSONImpl image; + + public MediaUploadResponseJSONImpl(final HttpResponse res) throws TwitterException { + super(res); + try { + init(res.asJSONObject()); + } catch (final JSONException e) { + throw new TwitterException(e); + } + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof MediaUploadResponseJSONImpl)) return false; + final MediaUploadResponseJSONImpl other = (MediaUploadResponseJSONImpl) obj; + if (id != other.id) return false; + return true; + } + + @Override + public long getId() { + return id; + } + + @Override + public Image getImage() { + return image; + } + + @Override + public long getSize() { + return size; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "MediaUploadResponseJSONImpl{id=" + id + ", size=" + size + ", image=" + image + "}"; + } + + private void init(final JSONObject json) throws JSONException { + if (json.isNull("image")) { + image = new ImageJSONImpl(json.getJSONObject("image")); + } + id = getLong("media_id", json); + size = getLong("size", json); + } + + static class ImageJSONImpl implements Image { + private final int width; + private final int height; + private final String imageType; + + public ImageJSONImpl(final JSONObject json) { + width = getInt("w", json); + height = getInt("h", json); + imageType = getRawString("image_type", json); + } + + @Override + public int getHeight() { + return height; + } + + @Override + public String getImageType() { + return imageType; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public String toString() { + return "ImageJSONImpl{width=" + width + ", height=" + height + ", imageType=" + imageType + "}"; + } + + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/OEmbedJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/OEmbedJSONImpl.java new file mode 100644 index 00000000..9a84a627 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/OEmbedJSONImpl.java @@ -0,0 +1,143 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.OEmbed; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 3.0.2 + */ +public class OEmbedJSONImpl extends TwitterResponseImpl implements OEmbed, java.io.Serializable { + private static final long serialVersionUID = -675438169712979958L; + private String html; + private String authorName; + private String url; + private String version; + private long cacheAge; + private String authorURL; + private int width; + + /* package */OEmbedJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */OEmbedJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final OEmbedJSONImpl that = (OEmbedJSONImpl) o; + + if (cacheAge != that.cacheAge) return false; + if (width != that.width) return false; + if (authorName != null ? !authorName.equals(that.authorName) : that.authorName != null) return false; + if (authorURL != null ? !authorURL.equals(that.authorURL) : that.authorURL != null) return false; + if (html != null ? !html.equals(that.html) : that.html != null) return false; + if (url != null ? !url.equals(that.url) : that.url != null) return false; + if (version != null ? !version.equals(that.version) : that.version != null) return false; + + return true; + } + + @Override + public String getAuthorName() { + return authorName; + } + + @Override + public String getAuthorURL() { + return authorURL; + } + + @Override + public long getCacheAge() { + return cacheAge; + } + + @Override + public String getHtml() { + return html; + } + + @Override + public String getURL() { + return url; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public int getWidth() { + return width; + } + + @Override + public int hashCode() { + int result = html != null ? html.hashCode() : 0; + result = 31 * result + (authorName != null ? authorName.hashCode() : 0); + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (version != null ? version.hashCode() : 0); + result = 31 * result + (int) (cacheAge ^ cacheAge >>> 32); + result = 31 * result + (authorURL != null ? authorURL.hashCode() : 0); + result = 31 * result + width; + return result; + } + + @Override + public String toString() { + return "OEmbedJSONImpl{" + "html='" + html + '\'' + ", authorName='" + authorName + '\'' + ", url='" + url + + '\'' + ", version='" + version + '\'' + ", cacheAge=" + cacheAge + ", authorURL='" + authorURL + '\'' + + ", width=" + width + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + html = json.getString("html"); + authorName = json.getString("author_name"); + url = json.getString("url"); + version = json.getString("version"); + cacheAge = json.getLong("cache_age"); + authorURL = json.getString("author_url"); + width = json.getInt("width"); + // provider_url provider_name, type always return same value + // there is no need to parse them and expose the values via OEmbed + // interface + // providerURL = json.getString("provider_url"); + // providerName = json.getString("provider_name"); + // type = json.getString("type"); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/PageableResponseListImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/PageableResponseListImpl.java new file mode 100644 index 00000000..eb975d51 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/PageableResponseListImpl.java @@ -0,0 +1,76 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONObject; + +import twitter4j.PageableResponseList; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +@SuppressWarnings("rawtypes") +class PageableResponseListImpl extends ResponseListImpl implements PageableResponseList { + private static final long serialVersionUID = 9098876089678648404L; + private final long previousCursor; + private final long nextCursor; + + PageableResponseListImpl(final int size, final JSONObject json, final HttpResponse res) { + super(size, res); + this.previousCursor = InternalParseUtil.getLong("previous_cursor", json); + this.nextCursor = InternalParseUtil.getLong("next_cursor", json); + } + + /** + * {@inheritDoc} + */ + @Override + public long getNextCursor() { + return nextCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public long getPreviousCursor() { + return previousCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasNext() { + return 0 != nextCursor; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasPrevious() { + return 0 != previousCursor; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/PlaceJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/PlaceJSONImpl.java new file mode 100644 index 00000000..b18dbcb1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/PlaceJSONImpl.java @@ -0,0 +1,263 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; + +import twitter4j.GeoLocation; +import twitter4j.Place; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +final class PlaceJSONImpl extends TwitterResponseImpl implements Place { + /** + * + */ + private static final long serialVersionUID = 2733342903542563480L; + private String name; + private String streetAddress; + private String countryCode; + private String id; + private String country; + private String placeType; + private String url; + private String fullName; + private String boundingBoxType; + private GeoLocation[][] boundingBoxCoordinates; + private String geometryType; + private GeoLocation[][] geometryCoordinates; + private Place[] containedWithIn; + + /* For serialization purposes only. */ + PlaceJSONImpl() { + + } + + /* package */PlaceJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + PlaceJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + PlaceJSONImpl(final JSONObject json, final HttpResponse res) throws TwitterException { + super(res); + init(json); + } + + @Override + public int compareTo(final Place that) { + return id.compareTo(that.getId()); + } + + @Override + public boolean equals(final Object obj) { + if (null == obj) return false; + if (this == obj) return true; + return obj instanceof Place && ((Place) obj).getId().equals(id); + } + + @Override + public GeoLocation[][] getBoundingBoxCoordinates() { + return boundingBoxCoordinates; + } + + @Override + public String getBoundingBoxType() { + return boundingBoxType; + } + + @Override + public Place[] getContainedWithIn() { + return containedWithIn; + } + + @Override + public String getCountry() { + return country; + } + + @Override + public String getCountryCode() { + return countryCode; + } + + @Override + public String getFullName() { + return fullName; + } + + @Override + public GeoLocation[][] getGeometryCoordinates() { + return geometryCoordinates; + } + + @Override + public String getGeometryType() { + return geometryType; + } + + @Override + public String getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getPlaceType() { + return placeType; + } + + @Override + public String getStreetAddress() { + return streetAddress; + } + + @Override + public String getURL() { + return url; + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public String toString() { + return "PlaceJSONImpl{" + "name='" + name + '\'' + ", streetAddress='" + streetAddress + '\'' + + ", countryCode='" + countryCode + '\'' + ", id='" + id + '\'' + ", country='" + country + '\'' + + ", placeType='" + placeType + '\'' + ", url='" + url + '\'' + ", fullName='" + fullName + '\'' + + ", boundingBoxType='" + boundingBoxType + '\'' + ", boundingBoxCoordinates=" + + (boundingBoxCoordinates == null ? null : Arrays.asList(boundingBoxCoordinates)) + ", geometryType='" + + geometryType + '\'' + ", geometryCoordinates=" + + (geometryCoordinates == null ? null : Arrays.asList(geometryCoordinates)) + ", containedWithIn=" + + (containedWithIn == null ? null : Arrays.asList(containedWithIn)) + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + name = getHTMLUnescapedString("name", json); + streetAddress = getHTMLUnescapedString("street_address", json); + countryCode = getRawString("country_code", json); + id = getRawString("id", json); + country = getRawString("country", json); + if (!json.isNull("place_type")) { + placeType = getRawString("place_type", json); + } else { + placeType = getRawString("type", json); + } + url = getRawString("url", json); + fullName = getRawString("full_name", json); + if (!json.isNull("bounding_box")) { + final JSONObject boundingBoxJSON = json.getJSONObject("bounding_box"); + boundingBoxType = getRawString("type", boundingBoxJSON); + final JSONArray array = boundingBoxJSON.getJSONArray("coordinates"); + boundingBoxCoordinates = InternalJSONFactoryImpl.coordinatesAsGeoLocationArray(array); + } else { + boundingBoxType = null; + boundingBoxCoordinates = null; + } + + if (!json.isNull("geometry")) { + final JSONObject geometryJSON = json.getJSONObject("geometry"); + geometryType = getRawString("type", geometryJSON); + final JSONArray array = geometryJSON.getJSONArray("coordinates"); + if (geometryType.equals("Point")) { + geometryCoordinates = new GeoLocation[1][1]; + geometryCoordinates[0][0] = new GeoLocation(array.getDouble(0), array.getDouble(1)); + } else if (geometryType.equals("Polygon")) { + geometryCoordinates = InternalJSONFactoryImpl.coordinatesAsGeoLocationArray(array); + } else { + // MultiPolygon currently unsupported. + geometryType = null; + geometryCoordinates = null; + } + } else { + geometryType = null; + geometryCoordinates = null; + } + + if (!json.isNull("contained_within")) { + final JSONArray containedWithInJSON = json.getJSONArray("contained_within"); + containedWithIn = new Place[containedWithInJSON.length()]; + for (int i = 0; i < containedWithInJSON.length(); i++) { + containedWithIn[i] = new PlaceJSONImpl(containedWithInJSON.getJSONObject(i)); + } + } else { + containedWithIn = null; + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + /* package */ + static ResponseList createPlaceList(final HttpResponse res, final Configuration conf) + throws TwitterException { + JSONObject json = null; + try { + json = res.asJSONObject(); + return createPlaceList(json.getJSONObject("result").getJSONArray("places"), res, conf); + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + /* package */ + static ResponseList createPlaceList(final JSONArray list, final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final int size = list.length(); + final ResponseList places = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final Place place = new PlaceJSONImpl(json); + places.add(place); + } + return places; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/QueryResultJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/QueryResultJSONImpl.java new file mode 100644 index 00000000..a69d1dd1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/QueryResultJSONImpl.java @@ -0,0 +1,186 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.Query; +import twitter4j.QueryResult; +import twitter4j.Status; +import twitter4j.TwitterException; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getDouble; +import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; +import static twitter4j.internal.util.InternalParseUtil.getURLDecodedString; + +/** + * A data class representing search API response + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +/* package */final class QueryResultJSONImpl extends ResponseListImpl implements QueryResult { + + private long sinceId; + private long maxId; + private String refreshUrl; + private int resultsPerPage; + private String warning; + private double completedIn; + private int page; + private String query; + + /* package */QueryResultJSONImpl(final HttpResponse res) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + try { + final JSONObject search_metadata = json.getJSONObject("search_metadata"); + sinceId = getLong("since_id", search_metadata); + maxId = getLong("max_id", search_metadata); + refreshUrl = getHTMLUnescapedString("refresh_url", search_metadata); + + resultsPerPage = getInt("results_per_page", search_metadata); + warning = getRawString("warning", search_metadata); + completedIn = getDouble("completed_in", search_metadata); + page = getInt("page", search_metadata); + query = getURLDecodedString("query", search_metadata); + final JSONArray array = json.getJSONArray("statuses"); + for (int i = 0, j = array.length(); i < j; i++) { + final JSONObject tweet = array.getJSONObject(i); + add(new StatusJSONImpl(tweet)); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + /* package */QueryResultJSONImpl(final HttpResponse res, final Query query) { + super(res); + sinceId = query.getSinceId(); + resultsPerPage = query.getRpp(); + page = query.getPage(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final QueryResult that = (QueryResult) o; + + if (Double.compare(that.getCompletedIn(), completedIn) != 0) return false; + if (maxId != that.getMaxId()) return false; + if (page != that.getPage()) return false; + if (resultsPerPage != that.getResultsPerPage()) return false; + if (sinceId != that.getSinceId()) return false; + if (!query.equals(that.getQuery())) return false; + if (refreshUrl != null ? !refreshUrl.equals(that.getRefreshUrl()) : that.getRefreshUrl() != null) + return false; + if (warning != null ? !warning.equals(that.getWarning()) : that.getWarning() != null) + return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public double getCompletedIn() { + return completedIn; + } + + /** + * {@inheritDoc} + */ + @Override + public long getMaxId() { + return maxId; + } + + /** + * {@inheritDoc} + */ + @Override + public int getPage() { + return page; + } + + /** + * {@inheritDoc} + */ + @Override + public String getQuery() { + return query; + } + + /** + * {@inheritDoc} + */ + @Override + public String getRefreshUrl() { + return refreshUrl; + } + + /** + * {@inheritDoc} + */ + @Override + public int getResultsPerPage() { + return resultsPerPage; + } + + /** + * {@inheritDoc} + */ + @Override + public long getSinceId() { + return sinceId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getWarning() { + return warning; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + long temp; + result = 31 * result + (int) (sinceId ^ (sinceId >>> 32)); + result = 31 * result + (int) (maxId ^ (maxId >>> 32)); + result = 31 * result + (refreshUrl != null ? refreshUrl.hashCode() : 0); + result = 31 * result + resultsPerPage; + result = 31 * result + (warning != null ? warning.hashCode() : 0); + temp = Double.doubleToLongBits(completedIn); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + page; + result = 31 * result + (query != null ? query.hashCode() : 0); + return result; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/RateLimitStatusJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/RateLimitStatusJSONImpl.java new file mode 100644 index 00000000..18437cd4 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/RateLimitStatusJSONImpl.java @@ -0,0 +1,194 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import twitter4j.RateLimitStatus; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getInt; + +/** + * A data class representing Twitter REST API's rate limit status + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see Rate Limiting | + * Twitter Developers + */ +/* package */final class RateLimitStatusJSONImpl implements RateLimitStatus, java.io.Serializable { + + private static final long serialVersionUID = 1625565652687304084L; + private int remaining; + private int limit; + private int resetTimeInSeconds; + private int secondsUntilReset; + + private RateLimitStatusJSONImpl(final int limit, final int remaining, final int resetTimeInSeconds) { + this.limit = limit; + this.remaining = remaining; + this.resetTimeInSeconds = resetTimeInSeconds; + secondsUntilReset = (int) ((resetTimeInSeconds * 1000L - System.currentTimeMillis()) / 1000); + } + + RateLimitStatusJSONImpl(final JSONObject json) throws TwitterException { + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final RateLimitStatusJSONImpl that = (RateLimitStatusJSONImpl) o; + + if (limit != that.limit) return false; + if (remaining != that.remaining) return false; + if (resetTimeInSeconds != that.resetTimeInSeconds) return false; + if (secondsUntilReset != that.secondsUntilReset) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int getLimit() { + return limit; + } + + /** + * {@inheritDoc} + */ + @Override + public int getRemaining() { + return remaining; + } + + /** + * {@inheritDoc} + */ + @Override + public int getRemainingHits() { + return getRemaining(); + } + + /** + * {@inheritDoc} + */ + @Override + public int getResetTimeInSeconds() { + return resetTimeInSeconds; + } + + /** + * {@inheritDoc} + */ + @Override + public int getSecondsUntilReset() { + return secondsUntilReset; + } + + @Override + public int hashCode() { + int result = remaining; + result = 31 * result + limit; + result = 31 * result + resetTimeInSeconds; + result = 31 * result + secondsUntilReset; + return result; + } + + @Override + public String toString() { + return "RateLimitStatusJSONImpl{" + "remaining=" + remaining + ", limit=" + limit + ", resetTimeInSeconds=" + + resetTimeInSeconds + ", secondsUntilReset=" + secondsUntilReset + '}'; + } + + void init(final JSONObject json) throws TwitterException { + limit = getInt("limit", json); + remaining = getInt("remaining", json); + resetTimeInSeconds = getInt("reset", json); + secondsUntilReset = (int) ((resetTimeInSeconds * 1000L - System.currentTimeMillis()) / 1000); + } + + static RateLimitStatus createFromResponseHeader(final HttpResponse res) { + if (null == res) return null; + int remainingHits;// "X-Rate-Limit-Remaining" + int limit;// "X-Rate-Limit-Limit" + int resetTimeInSeconds;// not included in the response header. Need to + // be calculated. + + final String strLimit = res.getResponseHeader("X-Rate-Limit-Limit"); + if (strLimit != null) { + limit = Integer.parseInt(strLimit); + } else + return null; + final String remaining = res.getResponseHeader("X-Rate-Limit-Remaining"); + if (remaining != null) { + remainingHits = Integer.parseInt(remaining); + } else + return null; + final String reset = res.getResponseHeader("X-Rate-Limit-Reset"); + if (reset != null) { + final long longReset = Long.parseLong(reset); + resetTimeInSeconds = (int) longReset; + } else + return null; + return new RateLimitStatusJSONImpl(limit, remainingHits, resetTimeInSeconds); + } + + static Map createRateLimitStatuses(final HttpResponse res, final Configuration conf) + throws TwitterException { + final JSONObject json = res.asJSONObject(); + final Map map = createRateLimitStatuses(json); + return map; + } + + static Map createRateLimitStatuses(final JSONObject json) throws TwitterException { + final Map map = new HashMap(); + try { + final JSONObject resources = json.getJSONObject("resources"); + final Iterator resourceKeys = resources.keys(); + while (resourceKeys.hasNext()) { + final JSONObject resource = resources.getJSONObject((String) resourceKeys.next()); + final Iterator endpointKeys = resource.keys(); + while (endpointKeys.hasNext()) { + final String endpoint = (String) endpointKeys.next(); + final JSONObject rateLimitStatusJSON = resource.getJSONObject(endpoint); + final RateLimitStatus rateLimitStatus = new RateLimitStatusJSONImpl(rateLimitStatusJSON); + map.put(endpoint, rateLimitStatus); + } + } + return Collections.unmodifiableMap(map); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/RelationshipJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/RelationshipJSONImpl.java new file mode 100644 index 00000000..72f58161 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/RelationshipJSONImpl.java @@ -0,0 +1,273 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.Relationship; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; +import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; +import static twitter4j.internal.util.InternalParseUtil.getLong; + +/** + * A data class that has detailed information about a relationship between two + * users + * + * @author Perry Sakkaris - psakkaris at gmail.com + * @see GET + * friendships/show | Twitter Developers + * @since Twitter4J 2.1.0 + */ +/* package */class RelationshipJSONImpl extends TwitterResponseImpl implements Relationship { + + private static final long serialVersionUID = 2816753598969317818L; + private final long targetUserId; + private final String targetUserScreenName; + private final boolean sourceBlockingTarget; + private final boolean sourceBlockedByTarget; + private final boolean sourceNotificationsEnabled; + private final boolean sourceFollowingTarget; + private final boolean sourceFollowedByTarget; + private final long sourceUserId; + private final String sourceUserScreenName; + private final boolean sourceCanDM; + private final boolean sourceCanMediaTag; + private final boolean sourceMutingTarget; + private final boolean sourceMarkedTargetAsSpam; + + /* package */RelationshipJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + this(res, res.asJSONObject()); + } + + /* package */RelationshipJSONImpl(final HttpResponse res, final JSONObject json) throws TwitterException { + super(res); + try { + final JSONObject relationship = json.getJSONObject("relationship"); + final JSONObject sourceJson = relationship.getJSONObject("source"); + final JSONObject targetJson = relationship.getJSONObject("target"); + sourceUserId = getLong("id", sourceJson); + targetUserId = getLong("id", targetJson); + sourceUserScreenName = getHTMLUnescapedString("screen_name", sourceJson); + targetUserScreenName = getHTMLUnescapedString("screen_name", targetJson); + sourceBlockingTarget = getBoolean("blocking", sourceJson); + sourceBlockedByTarget = getBoolean("blocked_by", sourceJson); + sourceFollowingTarget = getBoolean("following", sourceJson); + sourceFollowedByTarget = getBoolean("followed_by", sourceJson); + sourceNotificationsEnabled = getBoolean("notifications_enabled", sourceJson); + sourceCanDM = getBoolean("can_dm", sourceJson); + sourceCanMediaTag = getBoolean("can_media_tag", sourceJson); + sourceMutingTarget = getBoolean("muting", sourceJson); + sourceMarkedTargetAsSpam = getBoolean("marked_spam", sourceJson); + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + /* package */RelationshipJSONImpl(final JSONObject json) throws TwitterException { + this(null, json); + } + + @Override + public boolean canSourceDMTarget() { + return sourceCanDM; + } + + @Override + public boolean canSourceMediaTagTarget() { + return sourceCanMediaTag; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof RelationshipJSONImpl)) return false; + final RelationshipJSONImpl other = (RelationshipJSONImpl) obj; + if (sourceBlockingTarget != other.sourceBlockingTarget) return false; + if (sourceCanDM != other.sourceCanDM) return false; + if (sourceCanMediaTag != other.sourceCanMediaTag) return false; + if (sourceFollowedByTarget != other.sourceFollowedByTarget) return false; + if (sourceFollowingTarget != other.sourceFollowingTarget) return false; + if (sourceMarkedTargetAsSpam != other.sourceMarkedTargetAsSpam) return false; + if (sourceMutingTarget != other.sourceMutingTarget) return false; + if (sourceNotificationsEnabled != other.sourceNotificationsEnabled) return false; + if (sourceUserId != other.sourceUserId) return false; + if (sourceUserScreenName == null) { + if (other.sourceUserScreenName != null) return false; + } else if (!sourceUserScreenName.equals(other.sourceUserScreenName)) return false; + if (targetUserId != other.targetUserId) return false; + if (targetUserScreenName == null) { + if (other.targetUserScreenName != null) return false; + } else if (!targetUserScreenName.equals(other.targetUserScreenName)) return false; + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public long getSourceUserId() { + return sourceUserId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getSourceUserScreenName() { + return sourceUserScreenName; + } + + /** + * {@inheritDoc} + */ + @Override + public long getTargetUserId() { + return targetUserId; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTargetUserScreenName() { + return targetUserScreenName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (sourceBlockingTarget ? 1231 : 1237); + result = prime * result + (sourceCanDM ? 1231 : 1237); + result = prime * result + (sourceCanMediaTag ? 1231 : 1237); + result = prime * result + (sourceFollowedByTarget ? 1231 : 1237); + result = prime * result + (sourceFollowingTarget ? 1231 : 1237); + result = prime * result + (sourceMarkedTargetAsSpam ? 1231 : 1237); + result = prime * result + (sourceMutingTarget ? 1231 : 1237); + result = prime * result + (sourceNotificationsEnabled ? 1231 : 1237); + result = prime * result + (int) (sourceUserId ^ sourceUserId >>> 32); + result = prime * result + (sourceUserScreenName == null ? 0 : sourceUserScreenName.hashCode()); + result = prime * result + (int) (targetUserId ^ targetUserId >>> 32); + result = prime * result + (targetUserScreenName == null ? 0 : targetUserScreenName.hashCode()); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSourceBlockingTarget() { + return sourceBlockingTarget; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSourceBlockedByTarget() { + return sourceBlockedByTarget; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSourceFollowedByTarget() { + return sourceFollowedByTarget; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSourceFollowingTarget() { + return sourceFollowingTarget; + } + + @Override + public boolean isSourceMarkedTargetAsSpam() { + return sourceMarkedTargetAsSpam; + } + + @Override + public boolean isSourceMutingTarget() { + return sourceMutingTarget; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isSourceNotificationsEnabled() { + return sourceNotificationsEnabled; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isTargetFollowedBySource() { + return sourceFollowingTarget; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isTargetFollowingSource() { + return sourceFollowedByTarget; + } + + @Override + public String toString() { + return "RelationshipJSONImpl{targetUserId=" + targetUserId + ", targetUserScreenName=" + targetUserScreenName + + ", sourceBlockingTarget=" + sourceBlockingTarget + ", sourceNotificationsEnabled=" + + sourceNotificationsEnabled + ", sourceFollowingTarget=" + sourceFollowingTarget + + ", sourceFollowedByTarget=" + sourceFollowedByTarget + ", sourceUserId=" + sourceUserId + + ", sourceUserScreenName=" + sourceUserScreenName + ", sourceCanDM=" + sourceCanDM + + ", sourceCanMediaTag=" + sourceCanMediaTag + ", sourceMutingTarget=" + sourceMutingTarget + + ", sourceMarkedTargetAsSpam=" + sourceMarkedTargetAsSpam + "}"; + } + + /* package */ + static ResponseList createRelationshipList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONArray list = res.asJSONArray(); + final int size = list.length(); + final ResponseList relationships = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final Relationship relationship = new RelationshipJSONImpl(json); + relationships.add(relationship); + } + return relationships; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/ResponseListImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/ResponseListImpl.java new file mode 100644 index 00000000..a5805566 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/ResponseListImpl.java @@ -0,0 +1,62 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import java.util.ArrayList; + +import twitter4j.RateLimitStatus; +import twitter4j.ResponseList; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.3 + */ +class ResponseListImpl extends ArrayList implements ResponseList { + private static final long serialVersionUID = -7789068763212377625L; + private transient RateLimitStatus rateLimitStatus = null; + private transient int accessLevel; + + ResponseListImpl(final HttpResponse res) { + super(); + init(res); + } + + ResponseListImpl(final int size, final HttpResponse res) { + super(size); + init(res); + } + + @Override + public int getAccessLevel() { + return accessLevel; + } + + @Override + public RateLimitStatus getRateLimitStatus() { + return rateLimitStatus; + } + + private void init(final HttpResponse res) { + this.rateLimitStatus = RateLimitStatusJSONImpl.createFromResponseHeader(res); + accessLevel = InternalParseUtil.toAccessLevel(res); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/SavedSearchJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/SavedSearchJSONImpl.java new file mode 100644 index 00000000..029d3bdb --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/SavedSearchJSONImpl.java @@ -0,0 +1,164 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Date; + +import twitter4j.ResponseList; +import twitter4j.SavedSearch; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getDate; +import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; +import static twitter4j.internal.util.InternalParseUtil.getInt; + +/** + * A data class representing a Saved Search + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.8 + */ +/* package */final class SavedSearchJSONImpl extends TwitterResponseImpl implements SavedSearch { + + /** + * + */ + private static final long serialVersionUID = 3252481061731777994L; + private Date createdAt; + private String query; + private int position; + private String name; + private int id; + + /* package */SavedSearchJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */SavedSearchJSONImpl(final JSONObject savedSearch) throws TwitterException { + init(savedSearch); + } + + @Override + public int compareTo(final SavedSearch that) { + return id - that.getId(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof SavedSearch)) return false; + + final SavedSearch that = (SavedSearch) o; + + if (id != that.getId()) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getCreatedAt() { + return createdAt; + } + + /** + * {@inheritDoc} + */ + @Override + public int getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public int getPosition() { + return position; + } + + /** + * {@inheritDoc} + */ + @Override + public String getQuery() { + return query; + } + + @Override + public int hashCode() { + int result = createdAt.hashCode(); + result = 31 * result + query.hashCode(); + result = 31 * result + position; + result = 31 * result + name.hashCode(); + result = 31 * result + id; + return result; + } + + @Override + public String toString() { + return "SavedSearchJSONImpl{" + "createdAt=" + createdAt + ", query='" + query + '\'' + ", position=" + + position + ", name='" + name + '\'' + ", id=" + id + '}'; + } + + private void init(final JSONObject savedSearch) throws TwitterException { + createdAt = getDate("created_at", savedSearch, "EEE MMM dd HH:mm:ss z yyyy"); + query = getHTMLUnescapedString("query", savedSearch); + position = getInt("position", savedSearch); + name = getHTMLUnescapedString("name", savedSearch); + id = getInt("id", savedSearch); + } + + /* package */ + static ResponseList createSavedSearchList(final HttpResponse res, final Configuration conf) + throws TwitterException { + final JSONArray json = res.asJSONArray(); + ResponseList savedSearches; + try { + savedSearches = new ResponseListImpl(json.length(), res); + for (int i = 0; i < json.length(); i++) { + final JSONObject savedSearchesJSON = json.getJSONObject(i); + final SavedSearch savedSearch = new SavedSearchJSONImpl(savedSearchesJSON); + savedSearches.add(savedSearch); + } + return savedSearches; + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + res.asString(), jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/SimilarPlacesImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/SimilarPlacesImpl.java new file mode 100644 index 00000000..87a207bb --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/SimilarPlacesImpl.java @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.Place; +import twitter4j.ResponseList; +import twitter4j.SimilarPlaces; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.7 + */ +public class SimilarPlacesImpl extends ResponseListImpl implements SimilarPlaces { + + private static final long serialVersionUID = -5530218831645947540L; + private final String token; + + SimilarPlacesImpl(final ResponseList places, final HttpResponse res, final String token) { + super(places.size(), res); + this.addAll(places); + this.token = token; + } + + /** + * {@inheritDoc} + */ + @Override + public String getToken() { + return token; + } + + /* package */ + static SimilarPlaces createSimilarPlaces(final HttpResponse res, final Configuration conf) throws TwitterException { + JSONObject json = null; + try { + json = res.asJSONObject(); + final JSONObject result = json.getJSONObject("result"); + return new SimilarPlacesImpl(PlaceJSONImpl.createPlaceList(result.getJSONArray("places"), res, conf), res, + result.getString("token")); + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/StatusActivitySummaryJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/StatusActivitySummaryJSONImpl.java new file mode 100644 index 00000000..d1424de4 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/StatusActivitySummaryJSONImpl.java @@ -0,0 +1,144 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONObject; + +import twitter4j.IDs; +import twitter4j.StatusActivitySummary; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getLong; + +public class StatusActivitySummaryJSONImpl extends TwitterResponseImpl implements StatusActivitySummary { + + private static final long serialVersionUID = -8036116716122700832L; + + private IDs favoriters; + private IDs repliers; + + private IDs retweeters; + private long favoritersCount; + private long repliersCount; + private long retweetersCount; + private long descendentReplyCount; + + /* package */StatusActivitySummaryJSONImpl(final HttpResponse res, final Configuration conf) + throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */StatusActivitySummaryJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof StatusActivitySummaryJSONImpl)) return false; + final StatusActivitySummaryJSONImpl other = (StatusActivitySummaryJSONImpl) obj; + if (descendentReplyCount != other.descendentReplyCount) return false; + if (favoriters == null) { + if (other.favoriters != null) return false; + } else if (!favoriters.equals(other.favoriters)) return false; + if (favoritersCount != other.favoritersCount) return false; + if (repliers == null) { + if (other.repliers != null) return false; + } else if (!repliers.equals(other.repliers)) return false; + if (repliersCount != other.repliersCount) return false; + if (retweeters == null) { + if (other.retweeters != null) return false; + } else if (!retweeters.equals(other.retweeters)) return false; + if (retweetersCount != other.retweetersCount) return false; + return true; + } + + @Override + public long getDescendentReplyCount() { + return descendentReplyCount; + } + + @Override + public IDs getFavoriters() { + return favoriters; + } + + @Override + public long getFavoritersCount() { + return favoritersCount; + } + + @Override + public IDs getRepliers() { + return repliers; + } + + @Override + public long getRepliersCount() { + return repliersCount; + } + + @Override + public IDs getRetweeters() { + return retweeters; + } + + @Override + public long getRetweetersCount() { + return retweetersCount; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (descendentReplyCount ^ descendentReplyCount >>> 32); + result = prime * result + (favoriters == null ? 0 : favoriters.hashCode()); + result = prime * result + (int) (favoritersCount ^ favoritersCount >>> 32); + result = prime * result + (repliers == null ? 0 : repliers.hashCode()); + result = prime * result + (int) (repliersCount ^ repliersCount >>> 32); + result = prime * result + (retweeters == null ? 0 : retweeters.hashCode()); + result = prime * result + (int) (retweetersCount ^ retweetersCount >>> 32); + return result; + } + + @Override + public String toString() { + return "StatusActivitySummaryJSONImpl{favoriters=" + favoriters + ", repliers=" + repliers + ", retweeters=" + + retweeters + ", favoritersCount=" + favoritersCount + ", repliersCount=" + repliersCount + + ", retweetersCount=" + retweetersCount + ", descendentReplyCount=" + descendentReplyCount + "}"; + } + + private void init(final JSONObject json) throws TwitterException { + favoriters = new IDsJSONImpl(json.optString("favoriters")); + repliers = new IDsJSONImpl(json.optString("repliers")); + retweeters = new IDsJSONImpl(json.optString("retweeters")); + favoritersCount = getLong("favoriters_count", json); + repliersCount = getLong("repliers_count", json); + retweetersCount = getLong("retweeters_count", json); + descendentReplyCount = getLong("descendent_reply_count", json); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/StatusJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/StatusJSONImpl.java new file mode 100644 index 00000000..66168bf5 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/StatusJSONImpl.java @@ -0,0 +1,534 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.Date; + +import twitter4j.CardEntity; +import twitter4j.GeoLocation; +import twitter4j.HashtagEntity; +import twitter4j.MediaEntity; +import twitter4j.Place; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; +import twitter4j.URLEntity; +import twitter4j.User; +import twitter4j.UserMentionEntity; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.logging.Logger; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; +import static twitter4j.internal.util.InternalParseUtil.getDate; +import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; +import static twitter4j.internal.util.InternalParseUtil.getUnescapedString; + +/** + * A data class representing one single status of a user. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +final class StatusJSONImpl extends TwitterResponseImpl implements Status { + /** + * + */ + private static final long serialVersionUID = 8982739445731837548L; + + private static final Logger logger = Logger.getLogger(StatusJSONImpl.class); + + private Date createdAt; + private long id; + private String text; + private String rawText; + private String source; + private boolean isTruncated; + private long inReplyToStatusId; + private long inReplyToUserId; + private long currentUserRetweet; + private boolean isFavorited; + private String inReplyToScreenName; + private GeoLocation geoLocation = null; + private Place place = null; + private long retweetCount; + private long favoriteCount; + private CardEntity cardEntity; + + public long getReplyCount() { + return replyCount; + } + + public long getDescendentReplyCount() { + return descendentReplyCount; + } + + private long replyCount; + private long descendentReplyCount; + private boolean wasRetweetedByMe; + private boolean isPossiblySensitive; + + private String[] contributors = null; + private long[] contributorsIDs; + + private Status retweetedStatus; + private Status quotedStatus; + private UserMentionEntity[] userMentionEntities; + private URLEntity[] urlEntities; + private HashtagEntity[] hashtagEntities; + private MediaEntity[] mediaEntities; + private MediaEntity[] extendedMediaEntities; + + private User user = null; + + /* package */StatusJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */StatusJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public int compareTo(final Status that) { + final long delta = id - that.getId(); + if (delta < Integer.MIN_VALUE) + return Integer.MIN_VALUE; + else if (delta > Integer.MAX_VALUE) return Integer.MAX_VALUE; + return (int) delta; + } + + @Override + public boolean equals(final Object obj) { + if (null == obj) return false; + if (this == obj) return true; + return obj instanceof Status && ((Status) obj).getId() == id; + } + + /** + * {@inheritDoc} + */ + @Override + public long[] getContributors() { + if (contributors != null) { + // http://twitter4j.org/jira/browse/TFJ-592 + // preserving serialized form compatibility with older versions + contributorsIDs = new long[contributors.length]; + for (int i = 0; i < contributors.length; i++) { + try { + contributorsIDs[i] = Long.parseLong(contributors[i]); + } catch (final NumberFormatException nfe) { + nfe.printStackTrace(); + logger.warn("failed to parse contributors:" + nfe); + } + } + contributors = null; + } + return contributorsIDs; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getCreatedAt() { + return createdAt; + } + + @Override + public long getCurrentUserRetweet() { + return currentUserRetweet; + } + + @Override + public long getFavoriteCount() { + return favoriteCount; + } + + /** + * {@inheritDoc} + */ + @Override + public GeoLocation getGeoLocation() { + return geoLocation; + } + + /** + * {@inheritDoc} + */ + @Override + public HashtagEntity[] getHashtagEntities() { + return hashtagEntities; + } + + /** + * {@inheritDoc} + */ + @Override + public long getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getInReplyToScreenName() { + return inReplyToScreenName; + } + + /** + * {@inheritDoc} + */ + @Override + public long getInReplyToStatusId() { + return inReplyToStatusId; + } + + /** + * {@inheritDoc} + */ + @Override + public long getInReplyToUserId() { + return inReplyToUserId; + } + + /** + * {@inheritDoc} + */ + @Override + public MediaEntity[] getMediaEntities() { + return mediaEntities; + } + + /** + * {@inheritDoc} + */ + @Override + public Place getPlace() { + return place; + } + + @Override + public String getRawText() { + return rawText; + } + + /** + * {@inheritDoc} + */ + @Override + public long getRetweetCount() { + return retweetCount; + } + + /** + * {@inheritDoc} + */ + @Override + public Status getRetweetedStatus() { + return retweetedStatus; + } + + @Override + public Status getQuotedStatus() { + return quotedStatus; + } + + /** + * {@inheritDoc} + */ + @Override + public String getSource() { + return source; + } + + /** + * {@inheritDoc} + */ + @Override + public String getText() { + return text; + } + + /** + * {@inheritDoc} + */ + @Override + public URLEntity[] getURLEntities() { + return urlEntities; + } + + /** + * {@inheritDoc} + */ + @Override + public User getUser() { + return user; + } + + /** + * {@inheritDoc} + */ + @Override + public UserMentionEntity[] getUserMentionEntities() { + return userMentionEntities; + } + + @Override + public int hashCode() { + return (int) id; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isFavorited() { + return isFavorited; + } + + @Override + public boolean isPossiblySensitive() { + return isPossiblySensitive; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isRetweet() { + return retweetedStatus != null; + } + + @Override + public boolean isQuote() { + return quotedStatus != null; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isRetweetedByMe() { + return wasRetweetedByMe; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isTruncated() { + return isTruncated; + } + + @Override + public CardEntity getCard() { + return cardEntity; + } + + @Override + public String toString() { + return "StatusJSONImpl{createdAt=" + createdAt + ", id=" + id + ", text=" + text + ", rawText=" + rawText + + ", source=" + source + ", isTruncated=" + isTruncated + ", inReplyToStatusId=" + inReplyToStatusId + + ", inReplyToUserId=" + inReplyToUserId + ", currentUserRetweet=" + currentUserRetweet + + ", isFavorited=" + isFavorited + ", inReplyToScreenName=" + inReplyToScreenName + ", geoLocation=" + + geoLocation + ", place=" + place + ", retweetCount=" + retweetCount + ", wasRetweetedByMe=" + + wasRetweetedByMe + ", isPossiblySensitive=" + isPossiblySensitive + ", contributors=" + + Arrays.toString(contributors) + ", contributorsIDs=" + Arrays.toString(contributorsIDs) + + ", retweetedStatus=" + retweetedStatus + ", userMentionEntities=" + + Arrays.toString(userMentionEntities) + ", urlEntities=" + Arrays.toString(urlEntities) + + ", hashtagEntities=" + Arrays.toString(hashtagEntities) + ", mediaEntities=" + + Arrays.toString(mediaEntities) + ", user=" + user + "}"; + } + + private void init(final JSONObject json) throws TwitterException { + id = getLong("id", json); + rawText = getRawString("text", json); + text = getUnescapedString("text", json); + source = getHTMLUnescapedString("source", json); + createdAt = getDate("created_at", json); + isTruncated = getBoolean("truncated", json); + inReplyToStatusId = getLong("in_reply_to_status_id", json); + inReplyToUserId = getLong("in_reply_to_user_id", json); + isFavorited = getBoolean("favorited", json); + inReplyToScreenName = getHTMLUnescapedString("in_reply_to_screen_name", json); + isPossiblySensitive = getBoolean("possibly_sensitive", json); + retweetCount = getLong("retweet_count", json); + favoriteCount = getLong("favorite_count", json); + replyCount = getLong("reply_count", json); + descendentReplyCount = getLong("descendent_reply_count", json); + try { + if (!json.isNull("user")) { + user = new UserJSONImpl(json.getJSONObject("user")); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + geoLocation = InternalJSONFactoryImpl.createGeoLocation(json); + if (!json.isNull("place")) { + try { + place = new PlaceJSONImpl(json.getJSONObject("place")); + } catch (final JSONException ignore) { + ignore.printStackTrace(); + logger.warn("failed to parse place:" + json); + } + } + + if (!json.isNull("retweeted_status")) { + try { + retweetedStatus = new StatusJSONImpl(json.getJSONObject("retweeted_status")); + } catch (final JSONException ignore) { + ignore.printStackTrace(); + logger.warn("failed to parse retweeted_status:" + json); + } + } + + if (!json.isNull("quoted_status")) { + try { + quotedStatus = new StatusJSONImpl(json.getJSONObject("quoted_status")); + } catch (final JSONException ignore) { + ignore.printStackTrace(); + logger.warn("failed to parse retweeted_status:" + json); + } + } + + if (!json.isNull("contributors")) { + try { + final JSONArray contributorsArray = json.getJSONArray("contributors"); + contributorsIDs = new long[contributorsArray.length()]; + for (int i = 0; i < contributorsArray.length(); i++) { + contributorsIDs[i] = Long.parseLong(contributorsArray.getString(i)); + } + } catch (final NumberFormatException ignore) { + ignore.printStackTrace(); + logger.warn("failed to parse contributors:" + json); + } catch (final JSONException ignore) { + ignore.printStackTrace(); + logger.warn("failed to parse contributors:" + json); + } + } else { + contributors = null; + } + if (!json.isNull("entities")) { + try { + final JSONObject entities = json.getJSONObject("entities"); + int len; + if (!entities.isNull("user_mentions")) { + final JSONArray userMentionsArray = entities.getJSONArray("user_mentions"); + len = userMentionsArray.length(); + userMentionEntities = new UserMentionEntity[len]; + for (int i = 0; i < len; i++) { + userMentionEntities[i] = new UserMentionEntityJSONImpl(userMentionsArray.getJSONObject(i)); + } + } + if (!entities.isNull("urls")) { + final JSONArray urlsArray = entities.getJSONArray("urls"); + len = urlsArray.length(); + urlEntities = new URLEntity[len]; + for (int i = 0; i < len; i++) { + urlEntities[i] = new URLEntityJSONImpl(urlsArray.getJSONObject(i)); + } + } + if (!entities.isNull("hashtags")) { + final JSONArray hashtagsArray = entities.getJSONArray("hashtags"); + len = hashtagsArray.length(); + hashtagEntities = new HashtagEntity[len]; + for (int i = 0; i < len; i++) { + hashtagEntities[i] = new HashtagEntityJSONImpl(hashtagsArray.getJSONObject(i)); + } + } + if (!entities.isNull("media")) { + final JSONArray mediaArray = entities.getJSONArray("media"); + len = mediaArray.length(); + mediaEntities = new MediaEntity[len]; + for (int i = 0; i < len; i++) { + mediaEntities[i] = new MediaEntityJSONImpl(mediaArray.getJSONObject(i)); + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + if (!json.isNull("extended_entities")) { + try { + final JSONObject entities = json.getJSONObject("extended_entities"); + if (!entities.isNull("media")) { + int len; + final JSONArray mediaArray = entities.getJSONArray("media"); + len = mediaArray.length(); + extendedMediaEntities = new MediaEntity[len]; + for (int i = 0; i < len; i++) { + extendedMediaEntities[i] = new MediaEntityJSONImpl(mediaArray.getJSONObject(i)); + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + if (!json.isNull("current_user_retweet")) { + try { + currentUserRetweet = getLong("id", json.getJSONObject("current_user_retweet")); + wasRetweetedByMe = currentUserRetweet > 0; + } catch (final JSONException ignore) { + ignore.printStackTrace(); + logger.warn("failed to parse current_user_retweet:" + json); + } + } + if (!json.isNull("card")) { + try { + cardEntity = new CardEntityJSONImpl(json.getJSONObject("card")); + } catch (JSONException jsone) { + throw new TwitterException(jsone); + } + } + } + + /* package */ + static ResponseList createStatusList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONArray list = res.asJSONArray(); + final int size = list.length(); + final ResponseList statuses = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final Status status = new StatusJSONImpl(json); + statuses.add(status); + } + return statuses; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } + + @Override + public MediaEntity[] getExtendedMediaEntities() { + return extendedMediaEntities; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TimeZoneJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TimeZoneJSONImpl.java new file mode 100644 index 00000000..c8ee88c3 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TimeZoneJSONImpl.java @@ -0,0 +1,68 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.TimeZone; +import twitter4j.TwitterException; + +import static twitter4j.internal.util.InternalParseUtil.getInt; + +/** + * @author Alessandro Bahgat - ale.bahgat at gmail.com + */ +public class TimeZoneJSONImpl implements TimeZone { + + /** + * + */ + private static final long serialVersionUID = 4715603575648656436L; + private final String NAME; + private final String TZINFO_NAME; + private final int UTC_OFFSET; + + TimeZoneJSONImpl(final JSONObject jSONObject) throws TwitterException { + try { + UTC_OFFSET = getInt("utc_offset", jSONObject); + NAME = jSONObject.getString("name"); + TZINFO_NAME = jSONObject.getString("tzinfo_name"); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String tzinfoName() { + return TZINFO_NAME; + } + + @Override + public int utcOffset() { + return UTC_OFFSET; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TranslationResultJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TranslationResultJSONImpl.java new file mode 100644 index 00000000..0c8ea4de --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TranslationResultJSONImpl.java @@ -0,0 +1,126 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONObject; + +import twitter4j.TranslationResult; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; +import static twitter4j.internal.util.InternalParseUtil.getUnescapedString; + +public class TranslationResultJSONImpl extends TwitterResponseImpl implements TranslationResult { + + private static final long serialVersionUID = 2923323223626332587L; + private long id; + private String lang; + private String translatedLang; + private String translationType; + private String text; + + /* package */TranslationResultJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */TranslationResultJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof TranslationResultJSONImpl)) return false; + final TranslationResultJSONImpl other = (TranslationResultJSONImpl) obj; + if (id != other.id) return false; + if (lang == null) { + if (other.lang != null) return false; + } else if (!lang.equals(other.lang)) return false; + if (text == null) { + if (other.text != null) return false; + } else if (!text.equals(other.text)) return false; + if (translatedLang == null) { + if (other.translatedLang != null) return false; + } else if (!translatedLang.equals(other.translatedLang)) return false; + if (translationType == null) { + if (other.translationType != null) return false; + } else if (!translationType.equals(other.translationType)) return false; + return true; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getLang() { + return lang; + } + + @Override + public String getText() { + return text; + } + + @Override + public String getTranslatedLang() { + return translatedLang; + } + + @Override + public String getTranslationType() { + return translationType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (id ^ id >>> 32); + result = prime * result + (lang == null ? 0 : lang.hashCode()); + result = prime * result + (text == null ? 0 : text.hashCode()); + result = prime * result + (translatedLang == null ? 0 : translatedLang.hashCode()); + result = prime * result + (translationType == null ? 0 : translationType.hashCode()); + return result; + } + + @Override + public String toString() { + return "TranslationResultJSONImpl{id=" + id + ", lang=" + lang + ", translatedLang=" + translatedLang + + ", translationType=" + translationType + ", text=" + text + "}"; + } + + private void init(final JSONObject json) { + id = getLong("id", json); + lang = getRawString("lang", json); + translatedLang = getRawString("translated_lang", json); + translationType = getRawString("translation_type", json); + text = getUnescapedString("text", json); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TrendJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TrendJSONImpl.java new file mode 100644 index 00000000..b42de6d0 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TrendJSONImpl.java @@ -0,0 +1,99 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONObject; + +import twitter4j.Trend; + +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +/** + * A data class representing Trend. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.2 + */ +/* package */final class TrendJSONImpl implements Trend { + /** + * + */ + private static final long serialVersionUID = -2205410210175259078L; + private final String name; + private String url = null; + private String query = null; + + /* package */TrendJSONImpl(final JSONObject json) { + name = getRawString("name", json); + url = getRawString("url", json); + query = getRawString("query", json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Trend)) return false; + + final Trend trend = (Trend) o; + + if (!name.equals(trend.getName())) return false; + if (query != null ? !query.equals(trend.getQuery()) : trend.getQuery() != null) return false; + if (url != null ? !url.equals(trend.getUrl()) : trend.getUrl() != null) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getQuery() { + return query; + } + + /** + * {@inheritDoc} + */ + @Override + public String getUrl() { + return url; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (query != null ? query.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "TrendJSONImpl{" + "name='" + name + '\'' + ", url='" + url + '\'' + ", query='" + query + '\'' + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TrendsJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TrendsJSONImpl.java new file mode 100644 index 00000000..9c7c0e5f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TrendsJSONImpl.java @@ -0,0 +1,220 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; + +import twitter4j.Location; +import twitter4j.ResponseList; +import twitter4j.Trend; +import twitter4j.Trends; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; + +import static twitter4j.internal.util.InternalParseUtil.getDate; + +/** + * A data class representing Trends. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.0.2 + */ +/* package */final class TrendsJSONImpl extends TwitterResponseImpl implements Trends { + /** + * + */ + private static final long serialVersionUID = 9046543905431036999L; + private Date asOf; + private Date trendAt; + private Trend[] trends; + private Location location; + + /* package */TrendsJSONImpl(final Date asOf, final Location location, final Date trendAt, final Trend[] trends) { + this.asOf = asOf; + this.location = location; + this.trendAt = trendAt; + this.trends = trends; + } + + TrendsJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + init(res.asString()); + } + + TrendsJSONImpl(final String jsonStr) throws TwitterException { + init(jsonStr); + } + + @Override + public int compareTo(final Trends that) { + return trendAt.compareTo(that.getTrendAt()); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Trends)) return false; + + final Trends trends1 = (Trends) o; + + if (asOf != null ? !asOf.equals(trends1.getAsOf()) : trends1.getAsOf() != null) return false; + if (trendAt != null ? !trendAt.equals(trends1.getTrendAt()) : trends1.getTrendAt() != null) return false; + if (!Arrays.equals(trends, trends1.getTrends())) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getAsOf() { + return asOf; + } + + /** + * {@inheritDoc} + */ + @Override + public Location getLocation() { + return location; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getTrendAt() { + return trendAt; + } + + /** + * {@inheritDoc} + */ + @Override + public Trend[] getTrends() { + return trends; + } + + @Override + public int hashCode() { + int result = asOf != null ? asOf.hashCode() : 0; + result = 31 * result + (trendAt != null ? trendAt.hashCode() : 0); + result = 31 * result + (trends != null ? Arrays.hashCode(trends) : 0); + return result; + } + + @Override + public String toString() { + return "TrendsJSONImpl{" + "asOf=" + asOf + ", trendAt=" + trendAt + ", trends=" + + (trends == null ? null : Arrays.asList(trends)) + '}'; + } + + void init(final String jsonStr) throws TwitterException { + try { + JSONObject json; + if (jsonStr.startsWith("[")) { + final JSONArray array = new JSONArray(jsonStr); + if (array.length() > 0) { + json = array.getJSONObject(0); + } else + throw new TwitterException("No trends found on the specified woeid"); + } else { + json = new JSONObject(jsonStr); + } + asOf = InternalParseUtil.parseTrendsDate(json.getString("as_of")); + location = extractLocation(json); + final JSONArray array = json.getJSONArray("trends"); + trendAt = asOf; + trends = jsonArrayToTrendArray(array); + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage(), jsone); + } + } + + private static Location extractLocation(final JSONObject json) throws TwitterException { + if (json.isNull("locations")) return null; + ResponseList locations; + try { + locations = LocationJSONImpl.createLocationList(json.getJSONArray("locations")); + } catch (final JSONException e) { + throw new AssertionError("locations can't be null"); + } + Location location; + if (0 != locations.size()) { + location = locations.get(0); + } else { + location = null; + } + return location; + } + + private static Trend[] jsonArrayToTrendArray(final JSONArray array) throws JSONException { + final Trend[] trends = new Trend[array.length()]; + for (int i = 0; i < array.length(); i++) { + final JSONObject trend = array.getJSONObject(i); + trends[i] = new TrendJSONImpl(trend); + } + return trends; + } + + /* package */ + static ResponseList createTrendsList(final HttpResponse res, final boolean storeJSON) + throws TwitterException { + final JSONObject json = res.asJSONObject(); + ResponseList trends; + try { + final Date asOf = InternalParseUtil.parseTrendsDate(json.getString("as_of")); + final JSONObject trendsJson = json.getJSONObject("trends"); + final Location location = extractLocation(json); + trends = new ResponseListImpl(trendsJson.length(), res); + @SuppressWarnings("unchecked") + final Iterator ite = trendsJson.keys(); + while (ite.hasNext()) { + final String key = ite.next(); + final JSONArray array = trendsJson.getJSONArray(key); + final Trend[] trendsArray = jsonArrayToTrendArray(array); + if (key.length() == 19) { + // current trends + trends.add(new TrendsJSONImpl(asOf, location, getDate(key, "yyyy-MM-dd HH:mm:ss"), trendsArray)); + } else if (key.length() == 16) { + // daily trends + trends.add(new TrendsJSONImpl(asOf, location, getDate(key, "yyyy-MM-dd HH:mm"), trendsArray)); + } else if (key.length() == 10) { + // weekly trends + trends.add(new TrendsJSONImpl(asOf, location, getDate(key, "yyyy-MM-dd"), trendsArray)); + } + } + Collections.sort(trends); + return trends; + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + res.asString(), jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TwitterAPIConfigurationJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TwitterAPIConfigurationJSONImpl.java new file mode 100644 index 00000000..5346eecb --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TwitterAPIConfigurationJSONImpl.java @@ -0,0 +1,184 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import twitter4j.MediaEntity; +import twitter4j.TwitterAPIConfiguration; +import twitter4j.TwitterException; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getInt; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.2.3 + */ +class TwitterAPIConfigurationJSONImpl extends TwitterResponseImpl implements TwitterAPIConfiguration { + + /** + * + */ + private static final long serialVersionUID = 6112937720837291428L; + private int photoSizeLimit; + private int shortURLLength; + private int shortURLLengthHttps; + + private int charactersReservedPerMedia; + private Map photoSizes; + private String[] nonUsernamePaths; + private int maxMediaPerUpload; + + TwitterAPIConfigurationJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + try { + final JSONObject json = res.asJSONObject(); + photoSizeLimit = getInt("photo_size_limit", json); + shortURLLength = getInt("short_url_length", json); + shortURLLengthHttps = getInt("short_url_length_https", json); + charactersReservedPerMedia = getInt("characters_reserved_per_media", json); + + final JSONObject sizes = json.getJSONObject("photo_sizes"); + photoSizes = new HashMap(4); + photoSizes.put(MediaEntity.Size.LARGE, new MediaEntityJSONImpl.Size(sizes.getJSONObject("large"))); + JSONObject medium; + // http://code.google.com/p/twitter-api/issues/detail?id=2230 + if (sizes.isNull("med")) { + medium = sizes.getJSONObject("medium"); + } else { + medium = sizes.getJSONObject("med"); + } + photoSizes.put(MediaEntity.Size.MEDIUM, new MediaEntityJSONImpl.Size(medium)); + photoSizes.put(MediaEntity.Size.SMALL, new MediaEntityJSONImpl.Size(sizes.getJSONObject("small"))); + photoSizes.put(MediaEntity.Size.THUMB, new MediaEntityJSONImpl.Size(sizes.getJSONObject("thumb"))); + final JSONArray nonUsernamePathsJSONArray = json.getJSONArray("non_username_paths"); + nonUsernamePaths = new String[nonUsernamePathsJSONArray.length()]; + for (int i = 0; i < nonUsernamePathsJSONArray.length(); i++) { + nonUsernamePaths[i] = nonUsernamePathsJSONArray.getString(i); + } + maxMediaPerUpload = getInt("max_media_per_upload", json); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof TwitterAPIConfigurationJSONImpl)) return false; + + final TwitterAPIConfigurationJSONImpl that = (TwitterAPIConfigurationJSONImpl) o; + + if (charactersReservedPerMedia != that.charactersReservedPerMedia) return false; + if (maxMediaPerUpload != that.maxMediaPerUpload) return false; + if (photoSizeLimit != that.photoSizeLimit) return false; + if (shortURLLength != that.shortURLLength) return false; + if (shortURLLengthHttps != that.shortURLLengthHttps) return false; + if (!Arrays.equals(nonUsernamePaths, that.nonUsernamePaths)) return false; + if (photoSizes != null ? !photoSizes.equals(that.photoSizes) : that.photoSizes != null) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int getCharactersReservedPerMedia() { + return charactersReservedPerMedia; + } + + /** + * {@inheritDoc} + */ + @Override + public int getMaxMediaPerUpload() { + return maxMediaPerUpload; + } + + /** + * {@inheritDoc} + */ + @Override + public String[] getNonUsernamePaths() { + return nonUsernamePaths; + } + + /** + * {@inheritDoc} + */ + @Override + public int getPhotoSizeLimit() { + return photoSizeLimit; + } + + /** + * {@inheritDoc} + */ + @Override + public Map getPhotoSizes() { + return photoSizes; + } + + /** + * {@inheritDoc} + */ + @Override + public int getShortURLLength() { + return shortURLLength; + } + + /** + * {@inheritDoc} + */ + @Override + public int getShortURLLengthHttps() { + return shortURLLengthHttps; + } + + @Override + public int hashCode() { + int result = photoSizeLimit; + result = 31 * result + shortURLLength; + result = 31 * result + shortURLLengthHttps; + result = 31 * result + charactersReservedPerMedia; + result = 31 * result + (photoSizes != null ? photoSizes.hashCode() : 0); + result = 31 * result + (nonUsernamePaths != null ? Arrays.hashCode(nonUsernamePaths) : 0); + result = 31 * result + maxMediaPerUpload; + return result; + } + + @Override + public String toString() { + return "TwitterAPIConfigurationJSONImpl{" + "photoSizeLimit=" + photoSizeLimit + ", shortURLLength=" + + shortURLLength + ", shortURLLengthHttps=" + shortURLLengthHttps + ", charactersReservedPerMedia=" + + charactersReservedPerMedia + ", photoSizes=" + photoSizes + ", nonUsernamePaths=" + + (nonUsernamePaths == null ? null : Arrays.asList(nonUsernamePaths)) + ", maxMediaPerUpload=" + + maxMediaPerUpload + '}'; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TwitterResponseImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TwitterResponseImpl.java new file mode 100644 index 00000000..2a19e78f --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/TwitterResponseImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import twitter4j.RateLimitStatus; +import twitter4j.TwitterResponse; +import twitter4j.http.HttpResponse; +import twitter4j.internal.util.InternalParseUtil; + +/** + * Super interface of Twitter Response data interfaces which indicates that rate + * limit status is available. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @see twitter4j.DirectMessage + * @see twitter4j.Status + * @see twitter4j.User + */ +/* package */abstract class TwitterResponseImpl implements TwitterResponse { + + /** + * + */ + private static final long serialVersionUID = 8016245009711538262L; + + private transient RateLimitStatus rateLimitStatus = null; + + private transient int accessLevel; + + public TwitterResponseImpl() { + accessLevel = NONE; + } + + public TwitterResponseImpl(final HttpResponse res) { + rateLimitStatus = RateLimitStatusJSONImpl.createFromResponseHeader(res); + accessLevel = InternalParseUtil.toAccessLevel(res); + } + + /** + * {@inheritDoc} + */ + @Override + public int getAccessLevel() { + return accessLevel; + } + + /** + * {@inheritDoc} + */ + @Override + public RateLimitStatus getRateLimitStatus() { + return rateLimitStatus; + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/URLEntityJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/URLEntityJSONImpl.java new file mode 100644 index 00000000..7c0afd6d --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/URLEntityJSONImpl.java @@ -0,0 +1,160 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.TwitterException; +import twitter4j.URLEntity; + +/** + * A data class representing one single URL entity. + * + * @author Mocel - mocel at guma.jp + * @since Twitter4J 2.1.9 + */ +/* package */final class URLEntityJSONImpl implements URLEntity { + + /** + * + */ + private static final long serialVersionUID = 1326410198426703277L; + private int start = -1; + private int end = -1; + private String url; + private String expandedURL; + private String displayURL; + + /* For serialization purposes only. */ + /* package */URLEntityJSONImpl() { + + } + + /* package */URLEntityJSONImpl(final int start, final int end, final String url, final String expandedURL, + final String displayURL) { + super(); + this.start = start; + this.end = end; + this.url = url; + this.expandedURL = expandedURL; + this.displayURL = displayURL; + } + + /* package */URLEntityJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final URLEntityJSONImpl that = (URLEntityJSONImpl) o; + + if (end != that.end) return false; + if (start != that.start) return false; + if (displayURL != null ? !displayURL.equals(that.displayURL) : that.displayURL != null) + return false; + if (expandedURL != null ? !expandedURL.equalsIgnoreCase(that.expandedURL) + : that.expandedURL != null) return false; + if (url != null ? !url.equalsIgnoreCase(that.url) : that.url != null) + return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String getDisplayURL() { + return displayURL; + } + + /** + * {@inheritDoc} + */ + @Override + public int getEnd() { + return end; + } + + /** + * {@inheritDoc} + */ + @Override + public String getExpandedURL() { + return expandedURL; + } + + /** + * {@inheritDoc} + */ + @Override + public int getStart() { + return start; + } + + /** + * {@inheritDoc} + */ + @Override + public String getURL() { + return url; + } + + @Override + public int hashCode() { + int result = start; + result = 31 * result + end; + result = 31 * result + (url != null ? url.hashCode() : 0); + result = 31 * result + (expandedURL != null ? expandedURL.hashCode() : 0); + result = 31 * result + (displayURL != null ? displayURL.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "URLEntityJSONImpl{" + "start=" + start + ", end=" + end + ", url=" + url + ", expandedURL=" + + expandedURL + ", displayURL=" + displayURL + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + final JSONArray indicesArray = json.getJSONArray("indices"); + start = indicesArray.getInt(0); + end = indicesArray.getInt(1); + + url = json.getString("url"); + + if (!json.isNull("expanded_url")) { + expandedURL = json.getString("expanded_url"); + } + if (!json.isNull("display_url")) { + displayURL = json.getString("display_url"); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserJSONImpl.java new file mode 100644 index 00000000..5fb24f2e --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserJSONImpl.java @@ -0,0 +1,557 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Date; + +import twitter4j.PageableResponseList; +import twitter4j.ResponseList; +import twitter4j.Status; +import twitter4j.TwitterException; +import twitter4j.URLEntity; +import twitter4j.User; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; +import static twitter4j.internal.util.InternalParseUtil.getDate; +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +/** + * A data class representing Basic user information element + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +/* package */final class UserJSONImpl extends TwitterResponseImpl implements User { + private static final long serialVersionUID = 1401119968489672262L; + private long id; + private String name; + + private String screenName; + private String location; + private String description; + private boolean isContributorsEnabled; + private String profileImageUrl; + private String profileImageUrlHttps; + private String url; + private boolean isProtected; + private int followersCount; + private Status status; + private String profileBackgroundColor; + private String profileTextColor; + + private String profileLinkColor; + + private String profileSidebarFillColor; + private String profileSidebarBorderColor; + private boolean profileUseBackgroundImage; + private boolean showAllInlineMedia; + private int friendsCount; + private Date createdAt; + private int favouritesCount; + private int utcOffset; + private String timeZone; + private String profileBackgroundImageUrl; + private String profileBackgroundImageUrlHttps; + private boolean profileBackgroundTiled; + private String lang; + private int statusesCount; + private boolean isGeoEnabled; + private boolean isVerified; + private boolean isTranslator; + private boolean isFollowing; + private int listedCount; + private boolean isFollowRequestSent; + private String profileBannerImageUrl; + private boolean isDefaultProfileImage; + private URLEntity[] urlEntities; + private URLEntity[] descriptionEntities; + + /* package */UserJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + final JSONObject json = res.asJSONObject(); + init(json); + } + + /* package */UserJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public int compareTo(final User that) { + return (int) (id - that.getId()); + } + + @Override + public boolean equals(final Object obj) { + if (null == obj) return false; + if (this == obj) return true; + return obj instanceof User && ((User) obj).getId() == id; + } + + /** + * {@inheritDoc} + */ + @Override + public Date getCreatedAt() { + return createdAt; + } + + /** + * {@inheritDoc} + */ + @Override + public String getDescription() { + return description; + } + + @Override + public URLEntity[] getDescriptionEntities() { + return descriptionEntities; + } + + /** + * {@inheritDoc} + */ + @Override + public int getFavouritesCount() { + return favouritesCount; + } + + /** + * {@inheritDoc} + */ + @Override + public int getFollowersCount() { + return followersCount; + } + + /** + * {@inheritDoc} + */ + @Override + public int getFriendsCount() { + return friendsCount; + } + + /** + * {@inheritDoc} + */ + @Override + public long getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getLang() { + return lang; + } + + /** + * {@inheritDoc} + */ + @Override + public int getListedCount() { + return listedCount; + } + + /** + * {@inheritDoc} + */ + @Override + public String getLocation() { + return location; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileBackgroundColor() { + return profileBackgroundColor; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileBackgroundImageUrl() { + return profileBackgroundImageUrl; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileBackgroundImageUrlHttps() { + return profileBackgroundImageUrlHttps; + } + + @Override + public String getProfileBannerImageUrl() { + return profileBannerImageUrl; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileImageURL() { + return profileImageUrl; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileImageUrlHttps() { + return profileImageUrlHttps; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileLinkColor() { + return profileLinkColor; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileSidebarBorderColor() { + return profileSidebarBorderColor; + } + + /** + * {@inheritDoc} + */ + @Override + public String getProfileSidebarFillColor() { + return profileSidebarFillColor; + } + + @Override + public String getProfileTextColor() { + return profileTextColor; + } + + /** + * {@inheritDoc} + */ + @Override + public String getScreenName() { + return screenName; + } + + /** + * {@inheritDoc} + */ + @Override + public Status getStatus() { + return status; + } + + /** + * {@inheritDoc} + */ + @Override + public int getStatusesCount() { + return statusesCount; + } + + /** + * {@inheritDoc} + */ + @Override + public String getTimeZone() { + return timeZone; + } + + /** + * {@inheritDoc} + */ + @Override + public String getURL() { + return url; + } + + @Override + public URLEntity[] getURLEntities() { + return urlEntities; + } + + /** + * {@inheritDoc} + */ + @Override + public int getUtcOffset() { + return utcOffset; + } + + @Override + public int hashCode() { + return (int) id; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isContributorsEnabled() { + return isContributorsEnabled; + } + + @Override + public boolean isDefaultProfileImage() { + return isDefaultProfileImage; + } + + @Override + public boolean isFollowing() { + return isFollowing; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isFollowRequestSent() { + return isFollowRequestSent; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isGeoEnabled() { + return isGeoEnabled; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isProfileBackgroundTiled() { + return profileBackgroundTiled; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isProfileUseBackgroundImage() { + return profileUseBackgroundImage; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isProtected() { + return isProtected; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isShowAllInlineMedia() { + return showAllInlineMedia; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isTranslator() { + return isTranslator; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isVerified() { + return isVerified; + } + + @Override + public String toString() { + return "UserJSONImpl{" + "id=" + id + ", name='" + name + '\'' + ", screenName='" + screenName + '\'' + + ", location='" + location + '\'' + ", description='" + description + '\'' + + ", isContributorsEnabled=" + isContributorsEnabled + ", profileImageUrl='" + profileImageUrl + '\'' + + ", profileImageUrlHttps='" + profileImageUrlHttps + '\'' + ", url='" + url + '\'' + ", isProtected=" + + isProtected + ", followersCount=" + followersCount + ", status=" + status + + ", profileBackgroundColor='" + profileBackgroundColor + '\'' + ", profileTextColor='" + + profileTextColor + '\'' + ", profileLinkColor='" + profileLinkColor + '\'' + + ", profileSidebarFillColor='" + profileSidebarFillColor + '\'' + ", profileSidebarBorderColor='" + + profileSidebarBorderColor + '\'' + ", profileUseBackgroundImage=" + profileUseBackgroundImage + + ", showAllInlineMedia=" + showAllInlineMedia + ", friendsCount=" + friendsCount + ", createdAt=" + + createdAt + ", favouritesCount=" + favouritesCount + ", utcOffset=" + utcOffset + ", timeZone='" + + timeZone + '\'' + ", profileBackgroundImageUrl='" + profileBackgroundImageUrl + '\'' + + ", profileBackgroundImageUrlHttps='" + profileBackgroundImageUrlHttps + '\'' + + ", profileBackgroundTiled=" + profileBackgroundTiled + ", lang='" + lang + '\'' + ", statusesCount=" + + statusesCount + ", isGeoEnabled=" + isGeoEnabled + ", isVerified=" + isVerified + ", isTranslator=" + + isTranslator + ", listedCount=" + listedCount + ", isFollowRequestSent=" + isFollowRequestSent + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + id = getLong("id", json); + name = getRawString("name", json); + screenName = getRawString("screen_name", json); + location = getRawString("location", json); + description = getRawString("description", json); + isContributorsEnabled = getBoolean("contributors_enabled", json); + profileImageUrl = getRawString("profile_image_url", json); + profileImageUrlHttps = getRawString("profile_image_url_https", json); + url = getRawString("url", json); + isProtected = getBoolean("protected", json); + isGeoEnabled = getBoolean("geo_enabled", json); + isVerified = getBoolean("verified", json); + isTranslator = getBoolean("is_translator", json); + isFollowing = getBoolean("following", json); + followersCount = getInt("followers_count", json); + profileBannerImageUrl = getRawString("profile_banner_url", json); + profileBackgroundColor = getRawString("profile_background_color", json); + profileTextColor = getRawString("profile_text_color", json); + profileLinkColor = getRawString("profile_link_color", json); + profileSidebarFillColor = getRawString("profile_sidebar_fill_color", json); + profileSidebarBorderColor = getRawString("profile_sidebar_border_color", json); + profileUseBackgroundImage = getBoolean("profile_use_background_image", json); + showAllInlineMedia = getBoolean("show_all_inline_media", json); + friendsCount = getInt("friends_count", json); + createdAt = getDate("created_at", json, "EEE MMM dd HH:mm:ss z yyyy"); + favouritesCount = getInt("favourites_count", json); + utcOffset = getInt("utc_offset", json); + timeZone = getRawString("time_zone", json); + profileBackgroundImageUrl = getRawString("profile_background_image_url", json); + profileBackgroundImageUrlHttps = getRawString("profile_background_image_url_https", json); + profileBackgroundTiled = getBoolean("profile_background_tile", json); + lang = getRawString("lang", json); + statusesCount = getInt("statuses_count", json); + listedCount = getInt("listed_count", json); + isFollowRequestSent = getBoolean("follow_request_sent", json); + isDefaultProfileImage = getBoolean("default_profile_image", json); + if (!json.isNull("status")) { + final JSONObject statusJSON = json.getJSONObject("status"); + status = new StatusJSONImpl(statusJSON); + } + if (!json.isNull("entities")) { + try { + final JSONObject entities = json.getJSONObject("entities"); + int len; + if (!entities.isNull("description")) { + final JSONObject description = entities.getJSONObject("description"); + if (!description.isNull("urls")) { + final JSONArray urlsArray = description.getJSONArray("urls"); + len = urlsArray.length(); + descriptionEntities = new URLEntity[len]; + for (int i = 0; i < len; i++) { + descriptionEntities[i] = new URLEntityJSONImpl(urlsArray.getJSONObject(i)); + } + } + } + if (!entities.isNull("url")) { + final JSONObject url = entities.getJSONObject("url"); + if (!url.isNull("urls")) { + final JSONArray urlsArray = url.getJSONArray("urls"); + len = urlsArray.length(); + urlEntities = new URLEntity[len]; + for (int i = 0; i < len; i++) { + urlEntities[i] = new URLEntityJSONImpl(urlsArray.getJSONObject(i)); + } + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + /* package */ + static PageableResponseList createPagableUserList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONObject json = res.asJSONObject(); + final JSONArray list = json.getJSONArray("users"); + final int size = list.length(); + @SuppressWarnings("unchecked") + final PageableResponseList users = new PageableResponseListImpl(size, json, res); + for (int i = 0; i < size; i++) { + final JSONObject userJson = list.getJSONObject(i); + final User user = new UserJSONImpl(userJson); + users.add(user); + } + return users; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } + + /* package */ + static ResponseList createUserList(final HttpResponse res, final Configuration conf) throws TwitterException { + return createUserList(res.asJSONArray(), res, conf); + } + + /* package */ + static ResponseList createUserList(final JSONArray list, final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final int size = list.length(); + final ResponseList users = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject json = list.getJSONObject(i); + final User user = new UserJSONImpl(json); + users.add(user); + } + return users; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserListJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserListJSONImpl.java new file mode 100644 index 00000000..53657a1b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserListJSONImpl.java @@ -0,0 +1,261 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.URI; +import java.net.URISyntaxException; + +import twitter4j.PageableResponseList; +import twitter4j.ResponseList; +import twitter4j.TwitterException; +import twitter4j.User; +import twitter4j.UserList; +import twitter4j.conf.Configuration; +import twitter4j.http.HttpResponse; + +import static twitter4j.internal.util.InternalParseUtil.getBoolean; +import static twitter4j.internal.util.InternalParseUtil.getInt; +import static twitter4j.internal.util.InternalParseUtil.getLong; +import static twitter4j.internal.util.InternalParseUtil.getRawString; + +/** + * A data class representing Basic list information element + * + * @author Dan Checkoway - dcheckoway at gmail.com + */ +/* package */class UserListJSONImpl extends TwitterResponseImpl implements UserList { + + /** + * + */ + private static final long serialVersionUID = 2682622238509440140L; + private long id; + private String name; + private String fullName; + private String slug; + private String description; + private int subscriberCount; + private int memberCount; + private String uri; + private boolean mode; + private User user; + private boolean following; + + /* package */UserListJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { + super(res); + init(res.asJSONObject()); + } + + /* package */UserListJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public int compareTo(final UserList that) { + return (int) (id - that.getId()); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof UserListJSONImpl)) return false; + final UserListJSONImpl other = (UserListJSONImpl) obj; + if (id != other.id) return false; + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String getDescription() { + return description; + } + + /** + * {@inheritDoc} + */ + @Override + public String getFullName() { + return fullName; + } + + /** + * {@inheritDoc} + */ + @Override + public long getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public int getMemberCount() { + return memberCount; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getSlug() { + return slug; + } + + /** + * {@inheritDoc} + */ + @Override + public int getSubscriberCount() { + return subscriberCount; + } + + /** + * {@inheritDoc} + */ + @Override + public URI getURI() { + try { + return new URI(uri); + } catch (final URISyntaxException ex) { + return null; + } + } + + /** + * {@inheritDoc} + */ + @Override + public User getUser() { + return user; + } + + /* package */ + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (int) (id ^ id >>> 32); + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isFollowing() { + return following; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isPublic() { + return mode; + } + + @Override + public String toString() { + return "UserListJSONImpl{" + "id=" + id + ", name='" + name + '\'' + ", fullName='" + fullName + '\'' + + ", slug='" + slug + '\'' + ", description='" + description + '\'' + ", subscriberCount=" + + subscriberCount + ", memberCount=" + memberCount + ", uri='" + uri + '\'' + ", mode=" + mode + + ", user=" + user + ", following=" + following + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + id = getLong("id", json); + name = getRawString("name", json); + fullName = getRawString("full_name", json); + slug = getRawString("slug", json); + description = getRawString("description", json); + subscriberCount = getInt("subscriber_count", json); + memberCount = getInt("member_count", json); + uri = getRawString("uri", json); + mode = "public".equals(getRawString("mode", json)); + following = getBoolean("following", json); + + try { + if (!json.isNull("user")) { + user = new UserJSONImpl(json.getJSONObject("user")); + } + } catch (final JSONException jsone) { + throw new TwitterException(jsone.getMessage() + ":" + json.toString(), jsone); + } + } + + static PageableResponseList createPagableUserListList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONObject json = res.asJSONObject(); + final JSONArray list = json.getJSONArray("lists"); + final int size = list.length(); + @SuppressWarnings("unchecked") + final PageableResponseList users = new PageableResponseListImpl(size, json, res); + for (int i = 0; i < size; i++) { + final JSONObject userListJson = list.getJSONObject(i); + final UserList userList = new UserListJSONImpl(userListJson); + users.add(userList); + } + return users; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } + + /* package */ + static ResponseList createUserListList(final HttpResponse res, final Configuration conf) + throws TwitterException { + try { + final JSONArray list = res.asJSONArray(); + final int size = list.length(); + final ResponseList users = new ResponseListImpl(size, res); + for (int i = 0; i < size; i++) { + final JSONObject userListJson = list.getJSONObject(i); + final UserList userList = new UserListJSONImpl(userListJson); + users.add(userList); + } + return users; + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } catch (final TwitterException te) { + throw te; + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserMentionEntityJSONImpl.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserMentionEntityJSONImpl.java new file mode 100644 index 00000000..dc01f8ec --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/json/UserMentionEntityJSONImpl.java @@ -0,0 +1,154 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.json; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import twitter4j.TwitterException; +import twitter4j.UserMentionEntity; +import twitter4j.internal.util.InternalParseUtil; + +/** + * A data interface representing one single user mention entity. + * + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.9 + */ +/* package */class UserMentionEntityJSONImpl implements UserMentionEntity { + + /** + * + */ + private static final long serialVersionUID = 205671795665637553L; + private int start = -1; + private int end = -1; + private String name; + private String screenName; + private long id; + + /* For serialization purposes only. */ + /* package */UserMentionEntityJSONImpl() { + + } + + /* package */UserMentionEntityJSONImpl(final int start, final int end, final String name, final String screenName, + final long id) { + super(); + this.start = start; + this.end = end; + this.name = name; + this.screenName = screenName; + this.id = id; + } + + /* package */UserMentionEntityJSONImpl(final JSONObject json) throws TwitterException { + super(); + init(json); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final UserMentionEntityJSONImpl that = (UserMentionEntityJSONImpl) o; + + if (end != that.end) return false; + if (id != that.id) return false; + if (start != that.start) return false; + if (name != null ? !name.equals(that.name) : that.name != null) return false; + if (screenName != null ? !screenName.equals(that.screenName) : that.screenName != null) return false; + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public int getEnd() { + return end; + } + + /** + * {@inheritDoc} + */ + @Override + public long getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return name; + } + + /** + * {@inheritDoc} + */ + @Override + public String getScreenName() { + return screenName; + } + + /** + * {@inheritDoc} + */ + @Override + public int getStart() { + return start; + } + + @Override + public int hashCode() { + int result = start; + result = 31 * result + end; + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (screenName != null ? screenName.hashCode() : 0); + result = 31 * result + (int) (id ^ id >>> 32); + return result; + } + + @Override + public String toString() { + return "UserMentionEntityJSONImpl{" + "start=" + start + ", end=" + end + ", name='" + name + '\'' + + ", screenName='" + screenName + '\'' + ", id=" + id + '}'; + } + + private void init(final JSONObject json) throws TwitterException { + try { + final JSONArray indicesArray = json.getJSONArray("indices"); + start = indicesArray.getInt(0); + end = indicesArray.getInt(1); + + if (!json.isNull("name")) { + name = json.getString("name"); + } + if (!json.isNull("screen_name")) { + screenName = json.getString("screen_name"); + } + id = InternalParseUtil.getLong("id", json); + } catch (final JSONException jsone) { + throw new TwitterException(jsone); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/AndroidLogger.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/AndroidLogger.java new file mode 100644 index 00000000..472ddce2 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/AndroidLogger.java @@ -0,0 +1,152 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.logging; + +import android.util.Log; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +final class AndroidLogger extends Logger { + + private static final String DEFAULT_LOGTAG = "Twitter4J"; + + private final String logTag; + + AndroidLogger() { + logTag = DEFAULT_LOGTAG; + } + + AndroidLogger(final String tag) { + logTag = tag; + } + + /** + * {@inheritDoc} + */ + @Override + public void debug(final String message) { + if (isDebugEnabled()) { + Log.d(logTag, message); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void debug(final String message, final String message2) { + if (isDebugEnabled()) { + Log.d(logTag, message + message2); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void error(final String message) { + if (isErrorEnabled()) { + Log.e(logTag, message); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void error(final String message, final Throwable th) { + if (isErrorEnabled()) { + Log.e(logTag, message, th); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void info(final String message) { + if (isInfoEnabled()) { + Log.i(logTag, message); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void info(final String message, final String message2) { + if (isInfoEnabled()) { + Log.i(logTag, message + message2); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isDebugEnabled() { + return false; + // return Log.isLoggable(DEFAULT_LOGTAG, Log.DEBUG); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isErrorEnabled() { + return Log.isLoggable(DEFAULT_LOGTAG, Log.ERROR); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isInfoEnabled() { + return false; + // return Log.isLoggable(DEFAULT_LOGTAG, Log.INFO); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isWarnEnabled() { + return Log.isLoggable(DEFAULT_LOGTAG, Log.WARN); + } + + /** + * {@inheritDoc} + */ + @Override + public void warn(final String message) { + if (isWarnEnabled()) { + Log.w(logTag, message); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void warn(final String message, final String message2) { + if (isWarnEnabled()) { + Log.w(logTag, message + message2); + } + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/AndroidLoggerFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/AndroidLoggerFactory.java new file mode 100644 index 00000000..e77e8127 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/AndroidLoggerFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.logging; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +final class AndroidLoggerFactory extends LoggerFactory { + + @Override + public Logger getLogger() { + return new AndroidLogger(); + } + + @Override + public Logger getLogger(final Class clz) { + return new AndroidLogger(clz.getName()); + } + + @Override + public Logger getLogger(final String tag) { + return new AndroidLogger(tag); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/Logger.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/Logger.java new file mode 100644 index 00000000..cf72836c --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/Logger.java @@ -0,0 +1,119 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.logging; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.0 + */ +public abstract class Logger { + private static final LoggerFactory LOGGER_FACTORY = new AndroidLoggerFactory(); + + /** + * @param message message + */ + public abstract void debug(String message); + + /** + * @param message message + * @param message2 message2 + */ + public abstract void debug(String message, String message2); + + /** + * @param message message + */ + public abstract void error(String message); + + /** + * @param message message + * @param th throwable + */ + public abstract void error(String message, Throwable th); + + /** + * @param message message + */ + public abstract void info(String message); + + /** + * @param message message + * @param message2 message2 + */ + public abstract void info(String message, String message2); + + /** + * tests if debug level logging is enabled + * + * @return if debug level logging is enabled + */ + public abstract boolean isDebugEnabled(); + + /** + * tests if error level logging is enabled + * + * @return if error level logging is enabled + */ + public abstract boolean isErrorEnabled(); + + /** + * tests if info level logging is enabled + * + * @return if info level logging is enabled + */ + public abstract boolean isInfoEnabled(); + + /** + * tests if warn level logging is enabled + * + * @return if warn level logging is enabled + */ + public abstract boolean isWarnEnabled(); + + /** + * @param message message + */ + public abstract void warn(String message); + + /** + * @param message message + * @param message2 message2 + */ + public abstract void warn(String message, String message2); + + /** + * Returns a Logger instance associated with the specified class. + * + * @return logger instance + */ + @Deprecated + public static Logger getLogger() { + return LOGGER_FACTORY.getLogger(); + } + + public static Logger getLogger(final Class clz) { + return LOGGER_FACTORY.getLogger(clz); + } + + public static Logger getLogger(final String tag) { + return LOGGER_FACTORY.getLogger(tag); + } + +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/LoggerFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/LoggerFactory.java new file mode 100644 index 00000000..345edbc1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/LoggerFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.logging; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.1 + */ +public abstract class LoggerFactory { + + /** + * Returns a logger associated with the specified class. + * + * @return a logger instance + */ + public abstract Logger getLogger(); + + /** + * Returns a logger associated with the specified class. + * + * @return a logger instance + */ + public abstract Logger getLogger(Class clz); + + /** + * Returns a logger associated with the specified class. + * + * @return a logger instance + */ + public abstract Logger getLogger(String tag); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/NullLogger.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/NullLogger.java new file mode 100644 index 00000000..814c066b --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/NullLogger.java @@ -0,0 +1,111 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.logging; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.4 + */ +final class NullLogger extends Logger { + /** + * {@inheritDoc} + */ + @Override + public void debug(final String message) { + } + + /** + * {@inheritDoc} + */ + @Override + public void debug(final String message, final String message2) { + } + + /** + * {@inheritDoc} + */ + @Override + public void error(final String message) { + } + + /** + * {@inheritDoc} + */ + @Override + public void error(final String message, final Throwable th) { + } + + /** + * {@inheritDoc} + */ + @Override + public void info(final String message) { + } + + /** + * {@inheritDoc} + */ + @Override + public void info(final String message, final String message2) { + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isDebugEnabled() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isErrorEnabled() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isInfoEnabled() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isWarnEnabled() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void warn(final String message) { + } + + /** + * {@inheritDoc} + */ + @Override + public void warn(final String message, final String message2) { + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/NullLoggerFactory.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/NullLoggerFactory.java new file mode 100644 index 00000000..08c59574 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/logging/NullLoggerFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.logging; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.4 + */ +final class NullLoggerFactory extends LoggerFactory { + private static final Logger SINGLETON = new NullLogger(); + + /** + * {@inheritDoc} + */ + @Override + public Logger getLogger() { + return SINGLETON; + } + + @Override + public Logger getLogger(final Class clz) { + return SINGLETON; + } + + @Override + public Logger getLogger(final String tag) { + return SINGLETON; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/util/InternalParseUtil.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/util/InternalParseUtil.java new file mode 100644 index 00000000..c733cfda --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/util/InternalParseUtil.java @@ -0,0 +1,230 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.internal.util; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +import twitter4j.TwitterException; +import twitter4j.TwitterResponse; +import twitter4j.http.HTMLEntity; +import twitter4j.http.HttpResponse; + +/** + * A tiny parse utility class. + * + * @author Yusuke Yamamoto - yusuke at mac.com + */ +public final class InternalParseUtil { + private static ThreadLocal> formatMap = new ThreadLocal>() { + @Override + protected Map initialValue() { + return new HashMap(); + } + }; + + private InternalParseUtil() { + // should never be instantiated + throw new AssertionError(); + } + + public static boolean getBoolean(final String name, final JSONObject json) { + final String str = getRawString(name, json); + if (null == str || "null".equals(str)) return false; + return Boolean.valueOf(str); + } + + public static Date getDate(final String name, final JSONObject json) throws TwitterException { + return getDate(name, json, "EEE MMM d HH:mm:ss z yyyy"); + } + + public static Date getDate(final String name, final JSONObject json, final String format) throws TwitterException { + final String dateStr = getUnescapedString(name, json); + if ("null".equals(dateStr) || null == dateStr) + return null; + else + return getDate(dateStr, format); + } + + public static Date getDate(final String date, final String format) throws TwitterException { + SimpleDateFormat sdf = formatMap.get().get(format); + if (null == sdf) { + sdf = new SimpleDateFormat(format, Locale.ENGLISH); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + formatMap.get().put(format, sdf); + } + try { + return sdf.parse(date); + } catch (final ParseException pe) { + throw new TwitterException("Unexpected date format(" + date + ") returned from twitter.com", pe); + } + } + + public static double getDouble(final String name, final JSONObject json) { + final String str2 = getRawString(name, json); + if (null == str2 || "".equals(str2) || "null".equals(str2)) + return -1; + else + return Double.valueOf(str2); + } + + public static String getHTMLUnescapedString(final String name, final JSONObject json) { + return HTMLEntity.unescape(getRawString(name, json)); + } + + public static int getInt(final String str) { + if (null == str || "".equals(str) || "null".equals(str)) + return -1; + else { + try { + return Integer.valueOf(str); + } catch (final NumberFormatException nfe) { + // workaround for the API side issue + // http://twitter4j.org/jira/browse/TFJ-484 + return -1; + } + } + } + + public static int getInt(final String name, final JSONObject json) { + return getInt(getRawString(name, json)); + } + + public static long getLong(String str) { + if (null == str || "".equals(str) || "null".equals(str)) + return -1; + else { + try { + final Number number = NumberFormat.getInstance().parse(str); + return number.longValue(); + } catch (final ParseException e) { + } + // some count over 100 will be expressed as "100+" + if (str.endsWith("+")) { + str = str.substring(0, str.length() - 1); + try { + return Integer.valueOf(str) + 1; + } catch (final NumberFormatException nfe) { + // workaround for the API side issue + // http://twitter4j.org/jira/browse/TFJ-484 + return -1; + } + } + try { + return Long.valueOf(str); + } catch (final NumberFormatException nfe) { + // workaround for the API side issue + // http://twitter4j.org/jira/browse/TFJ-484 + return -1; + } + } + } + + public static long getLong(final String name, final JSONObject json) { + return getLong(getRawString(name, json)); + } + + public static String getRawString(final String name, final JSONObject json) { + try { + if (json.isNull(name)) return null; + return json.getString(name); + } catch (final JSONException e) { + return null; + } + } + + public static String getUnescapedString(final String name, final JSONObject json) { + final String str = getRawString(name, json); + if (str == null) return null; + return str.replace("&", "&").replace("<", "<").replace(">", ">"); + } + + public static String getURLDecodedString(final String name, final JSONObject json) { + String returnValue = getRawString(name, json); + if (returnValue != null) { + try { + returnValue = URLDecoder.decode(returnValue, "UTF-8"); + } catch (final UnsupportedEncodingException ignore) { + } + } + return returnValue; + } + + public static Date parseTrendsDate(final String asOfStr) throws TwitterException { + Date parsed; + switch (asOfStr.length()) { + case 10: + parsed = new Date(Long.parseLong(asOfStr) * 1000); + break; + case 20: + parsed = getDate(asOfStr, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + break; + default: + parsed = getDate(asOfStr, "EEE, d MMM yyyy HH:mm:ss z"); + } + return parsed; + } + + public static int toAccessLevel(final HttpResponse res) { + if (null == res) return -1; + final String xAccessLevel = res.getResponseHeader("X-Access-Level"); + int accessLevel; + if (null == xAccessLevel) { + accessLevel = TwitterResponse.NONE; + } else { + // https://dev.twitter.com/pages/application-permission-model-faq#how-do-we-know-what-the-access-level-of-a-user-token-is + switch (xAccessLevel.length()) { + // “read” (Read-only) + case 4: + accessLevel = TwitterResponse.READ; + break; + case 10: + // “read-write” (Read & Write) + accessLevel = TwitterResponse.READ_WRITE; + break; + case 25: + // “read-write-directmessages” (Read, Write, & Direct + // Message) + accessLevel = TwitterResponse.READ_WRITE_DIRECTMESSAGES; + break; + case 26: + // “read-write-privatemessages” (Read, Write, & Direct + // Message) + accessLevel = TwitterResponse.READ_WRITE_DIRECTMESSAGES; + break; + default: + accessLevel = TwitterResponse.NONE; + // unknown access level; + } + } + return accessLevel; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/internal/util/InternalStringUtil.java b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/util/InternalStringUtil.java new file mode 100644 index 00000000..44507da1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/internal/util/InternalStringUtil.java @@ -0,0 +1,101 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.internal.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.4 + */ +public class InternalStringUtil { + private InternalStringUtil() { + throw new AssertionError(); + } + + public static String join(final int[] array) { + final StringBuffer buf = new StringBuffer(11 * array.length); + for (final int follow : array) { + if (0 != buf.length()) { + buf.append(","); + } + buf.append(follow); + } + return buf.toString(); + } + + // for JDK1.4 compatibility + + public static String join(final long[] array) { + final StringBuffer buf = new StringBuffer(11 * array.length); + for (final long follow : array) { + if (0 != buf.length()) { + buf.append(","); + } + buf.append(follow); + } + return buf.toString(); + } + + public static String join(final String[] array) { + final StringBuffer buf = new StringBuffer(11 * array.length); + for (final String str : array) { + if (0 != buf.length()) { + buf.append(","); + } + buf.append(str); + } + return buf.toString(); + } + + public static String maskString(final String str) { + final StringBuffer buf = new StringBuffer(str.length()); + for (int i = 0; i < str.length(); i++) { + buf.append("*"); + } + return buf.toString(); + } + + public static String replaceLast(final String text, final String regex, final String replacement) { + if (text == null || regex == null || replacement == null) return text; + return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement); + } + + public static String[] split(final String str, final String separator) { + String[] returnValue; + int index = str.indexOf(separator); + if (index == -1) { + returnValue = new String[] { str }; + } else { + final List strList = new ArrayList(); + int oldIndex = 0; + while (index != -1) { + final String subStr = str.substring(oldIndex, index); + strList.add(subStr); + oldIndex = index + separator.length(); + index = str.indexOf(separator, oldIndex); + } + if (oldIndex != str.length()) { + strList.add(str.substring(oldIndex)); + } + returnValue = strList.toArray(new String[strList.size()]); + } + + return returnValue; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/lib/MyClass.java b/firetweet.component.twitter4j/src/main/java/twitter4j/lib/MyClass.java new file mode 100644 index 00000000..1d2f03a8 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/lib/MyClass.java @@ -0,0 +1,23 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package twitter4j.lib; + +public class MyClass { +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/management/APIStatistics.java b/firetweet.component.twitter4j/src/main/java/twitter4j/management/APIStatistics.java new file mode 100644 index 00000000..5c018b9a --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/management/APIStatistics.java @@ -0,0 +1,121 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.management; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Container for all InvocationStatisticsCalculators in a given API (like + * Twitter) + * + * @author Nick Dellamaggiore (nick.dellamaggiore gmail.com) + */ +public class APIStatistics implements APIStatisticsMBean { + private final InvocationStatisticsCalculator API_STATS_CALCULATOR; + private final Map METHOD_STATS_MAP; + private final int HISTORY_SIZE; + + /** + * @param historySize the number of calls to track (for invocation time + * averaging) + */ + public APIStatistics(final int historySize) { + API_STATS_CALCULATOR = new InvocationStatisticsCalculator("API", historySize); + METHOD_STATS_MAP = new HashMap(100); + HISTORY_SIZE = historySize; + } + + @Override + public long getAverageTime() { + return API_STATS_CALCULATOR.getAverageTime(); + } + + @Override + public long getCallCount() { + return API_STATS_CALCULATOR.getCallCount(); + } + + @Override + public long getErrorCount() { + return API_STATS_CALCULATOR.getErrorCount(); + } + + @Override + public synchronized Iterable getInvocationStatistics() { + return METHOD_STATS_MAP.values(); + } + + @Override + public synchronized Map getMethodLevelSummariesAsString() { + final Map summariesMap = new HashMap(); + + final Collection allMethodStats = METHOD_STATS_MAP.values(); + for (final InvocationStatisticsCalculator methodStats : allMethodStats) { + summariesMap.put(methodStats.getName(), methodStats.toString()); + } + + return summariesMap; + } + + @Override + public synchronized String getMethodLevelSummary(final String methodName) { + return METHOD_STATS_MAP.get(methodName).toString(); + } + + /** + * APIStatisticsMBean implementation + */ + + @Override + public String getName() { + return API_STATS_CALCULATOR.getName(); + } + + @Override + public long getTotalTime() { + return API_STATS_CALCULATOR.getTotalTime(); + } + + /** + * @param method the method invoked + * @param time the method execution time + */ + public synchronized void methodCalled(final String method, final long time, final boolean success) { + getMethodStatistics(method).increment(time, success); + + // increment for entire API + API_STATS_CALCULATOR.increment(time, success); + } + + @Override + public synchronized void reset() { + API_STATS_CALCULATOR.reset(); + METHOD_STATS_MAP.clear(); + } + + private synchronized InvocationStatisticsCalculator getMethodStatistics(final String method) { + InvocationStatisticsCalculator methodStats = METHOD_STATS_MAP.get(method); + + if (methodStats == null) { + methodStats = new InvocationStatisticsCalculator(method, HISTORY_SIZE); + METHOD_STATS_MAP.put(method, methodStats); + } + return methodStats; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/management/APIStatisticsMBean.java b/firetweet.component.twitter4j/src/main/java/twitter4j/management/APIStatisticsMBean.java new file mode 100644 index 00000000..9bbeaa74 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/management/APIStatisticsMBean.java @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.management; + +import java.util.Map; + +/** + * Simple MBean interface for APIStatistics. Method-level statistics are exposed + * as a Map of formatted strings + * + * @author Nick Dellamaggiore (nick.dellamaggiore gmail.com) + */ +public interface APIStatisticsMBean extends InvocationStatistics { + public Iterable getInvocationStatistics(); + + public Map getMethodLevelSummariesAsString(); + + public String getMethodLevelSummary(String methodName); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/management/InvocationStatistics.java b/firetweet.component.twitter4j/src/main/java/twitter4j/management/InvocationStatistics.java new file mode 100644 index 00000000..fd0ea903 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/management/InvocationStatistics.java @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.management; + +/** + * @author Nick Dellamaggiore (nick.dellamaggiore gmail.com) + */ +public interface InvocationStatistics { + public long getAverageTime(); + + public long getCallCount(); + + public long getErrorCount(); + + public String getName(); + + public long getTotalTime(); + + public void reset(); +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/management/InvocationStatisticsCalculator.java b/firetweet.component.twitter4j/src/main/java/twitter4j/management/InvocationStatisticsCalculator.java new file mode 100644 index 00000000..447a9d67 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/management/InvocationStatisticsCalculator.java @@ -0,0 +1,106 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.management; + +/** + * Object that collects/aggregates statistics for the invocation of a given + * method. + * + * @author Nick Dellamaggiore (nick.dellamaggiore gmail.com) + */ +public class InvocationStatisticsCalculator implements InvocationStatistics { + private final String name; + private long[] times; + private int index; + private long callCount; + private long errorCount; + private long totalTime; + + /** + * @param name the name of this API method + * @param historySize the number of calls to track (for invocation time + * averaging) + */ + public InvocationStatisticsCalculator(final String name, final int historySize) { + this.name = name; + times = new long[historySize]; + } + + @Override + public synchronized long getAverageTime() { + final int stopIndex = Math.min(Math.abs((int) callCount), times.length); + if (stopIndex == 0) return 0; + + long totalTime = 0; + for (int i = 0; i < stopIndex; i++) { + totalTime += times[i]; + + } + return totalTime / stopIndex; + } + + @Override + public long getCallCount() { + return callCount; + } + + @Override + public long getErrorCount() { + return errorCount; + } + + @Override + public String getName() { + return name; + } + + @Override + public long getTotalTime() { + return totalTime; + } + + public void increment(final long time, final boolean success) { + callCount++; + errorCount += success ? 0 : 1; + totalTime += time; + + times[index] = time; + + if (++index >= times.length) { + index = 0; + } + } + + @Override + public synchronized void reset() { + callCount = 0; + errorCount = 0; + totalTime = 0; + times = new long[times.length]; + index = 0; + } + + @Override + public String toString() { + // StringBuilder is faster... do we still need to support JDK 1.4? + final StringBuffer sb = new StringBuffer(); + sb.append("calls=").append(getCallCount()).append(",").append("errors=").append(getErrorCount()).append(",") + .append("totalTime=").append(getTotalTime()).append(",").append("avgTime=").append(getAverageTime()); + + return sb.toString(); + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/util/CharacterUtil.java b/firetweet.component.twitter4j/src/main/java/twitter4j/util/CharacterUtil.java new file mode 100644 index 00000000..b4e6e0e1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/util/CharacterUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.util; + +/** + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.2 + */ +public final class CharacterUtil { + private CharacterUtil() { + throw new AssertionError(); + } + + /** + * Counts the length of the tweet + * + * @param text tweet to be counted + * @return the length of the tweet + */ + public static int count(final String text) { + return text.length(); + } + + /** + * Returns true if the length of the string is exceeding length limitation + * + * @param text String to be examined + * @return if the length of the string is exceeding length limitation + */ + public static boolean isExceedingLengthLimitation(final String text) { + return count(text) > 140; + } +} diff --git a/firetweet.component.twitter4j/src/main/java/twitter4j/util/TimeSpanConverter.java b/firetweet.component.twitter4j/src/main/java/twitter4j/util/TimeSpanConverter.java new file mode 100644 index 00000000..3b91aec1 --- /dev/null +++ b/firetweet.component.twitter4j/src/main/java/twitter4j/util/TimeSpanConverter.java @@ -0,0 +1,155 @@ +/* + * Copyright 2007 Yusuke Yamamoto + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package twitter4j.util; + +import java.text.MessageFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * @author Joern Huxhorn - jhuxhorn at googlemail.com + * @author Yusuke Yamamoto - yusuke at mac.com + * @since Twitter4J 2.1.0 + */ +public final class TimeSpanConverter { + private static final int ONE_HOUR_IN_SECONDS = 60 * 60; + private static final int ONE_DAY_IN_SECONDS = 24 * ONE_HOUR_IN_SECONDS; + private static final int ONE_MONTH_IN_SECONDS = 30 * ONE_DAY_IN_SECONDS; + + private final MessageFormat[] formats = new MessageFormat[6]; + private final SimpleDateFormat dateMonth; + private final SimpleDateFormat dateMonthYear; + + private static final int NOW = 0; + private static final int N_SECONDS_AGO = 1; + private static final int A_MINUTE_AGO = 2; + private static final int N_MINUTES_AGO = 3; + private static final int AN_HOUR_AGO = 4; + private static final int N_HOURS_AGO = 5; + + /** + * Constructs an instance with default locale + */ + public TimeSpanConverter() { + this(Locale.getDefault()); + } + + /** + * Constructs an instance with the specified locale + * + * @param locale locale + */ + public TimeSpanConverter(final Locale locale) { + final String language = locale.getLanguage(); + if ("it".equals(language)) { + formats[NOW] = new MessageFormat("Ora"); + formats[N_SECONDS_AGO] = new MessageFormat("{0} secondi fa"); + formats[A_MINUTE_AGO] = new MessageFormat("1 minuto fa"); + formats[N_MINUTES_AGO] = new MessageFormat("{0} minuti fa"); + formats[AN_HOUR_AGO] = new MessageFormat("1 ora fa"); + formats[N_HOURS_AGO] = new MessageFormat("{0} ore fa"); + dateMonth = new SimpleDateFormat("d MMM", locale); + dateMonthYear = new SimpleDateFormat("d MMM yy", locale); + } else if ("kr".equals(language)) { + formats[NOW] = new MessageFormat("지금"); + formats[N_SECONDS_AGO] = new MessageFormat("{0}초 전"); + formats[A_MINUTE_AGO] = new MessageFormat("1분 전"); + formats[N_MINUTES_AGO] = new MessageFormat("{0}분 전"); + formats[AN_HOUR_AGO] = new MessageFormat("1시간 전"); + formats[N_HOURS_AGO] = new MessageFormat("{0} ore fa"); + dateMonth = new SimpleDateFormat("M월 d일", locale); + dateMonthYear = new SimpleDateFormat("yy년 M월 d일", locale); + } else if ("es".equals(language)) { + formats[NOW] = new MessageFormat("Ahora"); + formats[N_SECONDS_AGO] = new MessageFormat("hace {0} segundos"); + formats[A_MINUTE_AGO] = new MessageFormat("hace 1 munito"); + formats[N_MINUTES_AGO] = new MessageFormat("hace {0} munitos"); + formats[AN_HOUR_AGO] = new MessageFormat("hace 1 hora"); + formats[N_HOURS_AGO] = new MessageFormat("hace {0} horas"); + dateMonth = new SimpleDateFormat("d MMM", locale); + dateMonthYear = new SimpleDateFormat("d MMM yy", locale); + } else if ("fr".equals(language)) { + formats[NOW] = new MessageFormat("Maintenant"); + formats[N_SECONDS_AGO] = new MessageFormat("Il y a {0} secondes"); + formats[A_MINUTE_AGO] = new MessageFormat("Il y a 1 minute"); + formats[N_MINUTES_AGO] = new MessageFormat("Il y a {0} minutes"); + formats[AN_HOUR_AGO] = new MessageFormat("Il y a 1 heure"); + formats[N_HOURS_AGO] = new MessageFormat("Il y a {0} heures"); + dateMonth = new SimpleDateFormat("d MMM", locale); + dateMonthYear = new SimpleDateFormat("d MMM yy", locale); + } else if ("de".equals(language)) { + formats[NOW] = new MessageFormat("Jetzt"); + formats[N_SECONDS_AGO] = new MessageFormat("vor {0} Sekunden"); + formats[A_MINUTE_AGO] = new MessageFormat("vor 1 Minute"); + formats[N_MINUTES_AGO] = new MessageFormat("vor {0} Minuten"); + formats[AN_HOUR_AGO] = new MessageFormat("vor 1 Stunde"); + formats[N_HOURS_AGO] = new MessageFormat("vor {0} Stunden"); + dateMonth = new SimpleDateFormat("d MMM", locale); + dateMonthYear = new SimpleDateFormat("d MMM yy", locale); + } else if ("ja".equals(language)) { + formats[NOW] = new MessageFormat("今"); + formats[N_SECONDS_AGO] = new MessageFormat("{0}秒前"); + formats[A_MINUTE_AGO] = new MessageFormat("1分前"); + formats[N_MINUTES_AGO] = new MessageFormat("{0}分前"); + formats[AN_HOUR_AGO] = new MessageFormat("1時間前"); + formats[N_HOURS_AGO] = new MessageFormat("{0}時間前"); + dateMonth = new SimpleDateFormat("M月d日", locale); + dateMonthYear = new SimpleDateFormat("yy年M月d日", locale); + } else { + formats[NOW] = new MessageFormat("now"); + formats[N_SECONDS_AGO] = new MessageFormat("{0} seconds ago"); + formats[A_MINUTE_AGO] = new MessageFormat("1 minute ago"); + formats[N_MINUTES_AGO] = new MessageFormat("{0} minutes ago"); + formats[AN_HOUR_AGO] = new MessageFormat("1 hour ago"); + formats[N_HOURS_AGO] = new MessageFormat("{0} hours ago"); + dateMonth = new SimpleDateFormat("d MMM", Locale.ENGLISH); + dateMonthYear = new SimpleDateFormat("d MMM yy", Locale.ENGLISH); + } + } + + public String toTimeSpanString(final Date date) { + return toTimeSpanString(date.getTime()); + } + + public String toTimeSpanString(final long milliseconds) { + final int deltaInSeconds = (int) ((System.currentTimeMillis() - milliseconds) / 1000); + if (deltaInSeconds >= ONE_DAY_IN_SECONDS) { + if (deltaInSeconds >= ONE_MONTH_IN_SECONDS) + return dateMonthYear.format(new Date(milliseconds)); + else + return dateMonth.format(new Date(milliseconds)); + } + return toTimeSpanString(deltaInSeconds); + } + + private String toTimeSpanString(final int deltaInSeconds) { + if (deltaInSeconds <= 1) + return formats[NOW].format(null); + else if (deltaInSeconds < 60) return formats[N_SECONDS_AGO].format(new Object[] { deltaInSeconds }); + + if (deltaInSeconds < 45 * 60) { + final int minutes = deltaInSeconds / 60; + if (minutes == 1) return formats[A_MINUTE_AGO].format(null); + return formats[N_MINUTES_AGO].format(new Object[] { minutes }); + } + + if (deltaInSeconds < 105 * 60) return formats[AN_HOUR_AGO].format(null); + final int hours = (deltaInSeconds + 15 * 60) / ONE_HOUR_IN_SECONDS; + return formats[N_HOURS_AGO].format(new Object[] { hours }); + } +} diff --git a/firetweet.donate.nyanwp.wear/.gitignore b/firetweet.donate.nyanwp.wear/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.donate.nyanwp.wear/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.donate.nyanwp.wear/build.gradle b/firetweet.donate.nyanwp.wear/build.gradle new file mode 100644 index 00000000..7e0d2ef0 --- /dev/null +++ b/firetweet.donate.nyanwp.wear/build.gradle @@ -0,0 +1,42 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.application' +apply from: rootProject.file('global.gradle') +apply from: rootProject.file('signing.gradle') + +android { + defaultConfig { + applicationId "org.getlantern.firetweet.donate.nyanwp" + minSdkVersion 20 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } +} + +dependencies { + compile 'com.google.android.support:wearable:1.1.0' + compile project(':firetweet.component.nyan') + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.donate.nyanwp.wear/proguard-rules.pro b/firetweet.donate.nyanwp.wear/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.donate.nyanwp.wear/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.donate.nyanwp.wear/src/main/AndroidManifest.xml b/firetweet.donate.nyanwp.wear/src/main/AndroidManifest.xml new file mode 100644 index 00000000..c5fc9905 --- /dev/null +++ b/firetweet.donate.nyanwp.wear/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + diff --git a/firetweet.donate.nyanwp.wear/src/main/java/org/getlantern/firetweet/donate/nyanwp/NyanActivity.java b/firetweet.donate.nyanwp.wear/src/main/java/org/getlantern/firetweet/donate/nyanwp/NyanActivity.java new file mode 100644 index 00000000..ba5d47ca --- /dev/null +++ b/firetweet.donate.nyanwp.wear/src/main/java/org/getlantern/firetweet/donate/nyanwp/NyanActivity.java @@ -0,0 +1,44 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.donate.nyanwp; + +import android.app.Activity; +import android.os.Bundle; +import android.support.wearable.view.WatchViewStub; +import android.support.wearable.view.WatchViewStub.OnLayoutInflatedListener; + +import org.getlantern.firetweet.nyan.NyanDaydreamView; + +public class NyanActivity extends Activity implements OnLayoutInflatedListener { + + @Override + public void onLayoutInflated(WatchViewStub watchViewStub) { + final NyanDaydreamView nyanView = (NyanDaydreamView) watchViewStub.findViewById(R.id.nyan_view); + nyanView.setScale(getResources().getInteger(R.integer.default_live_wallpaper_scale)); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_nyan); + final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); + stub.setOnLayoutInflatedListener(this); + } +} diff --git a/firetweet.donate.nyanwp.wear/src/main/res/drawable-hdpi/ic_launcher.png b/firetweet.donate.nyanwp.wear/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100755 index 00000000..09b2de4b Binary files /dev/null and b/firetweet.donate.nyanwp.wear/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp.wear/src/main/res/drawable-mdpi/ic_launcher.png b/firetweet.donate.nyanwp.wear/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100755 index 00000000..29d52d1b Binary files /dev/null and b/firetweet.donate.nyanwp.wear/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp.wear/src/main/res/drawable-xhdpi/ic_launcher.png b/firetweet.donate.nyanwp.wear/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100755 index 00000000..2cd6045e Binary files /dev/null and b/firetweet.donate.nyanwp.wear/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp.wear/src/main/res/drawable-xxhdpi/ic_launcher.png b/firetweet.donate.nyanwp.wear/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100755 index 00000000..7079aa91 Binary files /dev/null and b/firetweet.donate.nyanwp.wear/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp.wear/src/main/res/drawable-xxxhdpi/ic_launcher.png b/firetweet.donate.nyanwp.wear/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100755 index 00000000..b4d69c78 Binary files /dev/null and b/firetweet.donate.nyanwp.wear/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp.wear/src/main/res/layout/activity_nyan.xml b/firetweet.donate.nyanwp.wear/src/main/res/layout/activity_nyan.xml new file mode 100644 index 00000000..1c23a928 --- /dev/null +++ b/firetweet.donate.nyanwp.wear/src/main/res/layout/activity_nyan.xml @@ -0,0 +1,32 @@ + + + + + diff --git a/firetweet.donate.nyanwp.wear/src/main/res/layout/rect_activity_nyan.xml b/firetweet.donate.nyanwp.wear/src/main/res/layout/rect_activity_nyan.xml new file mode 100644 index 00000000..6e0029cb --- /dev/null +++ b/firetweet.donate.nyanwp.wear/src/main/res/layout/rect_activity_nyan.xml @@ -0,0 +1,29 @@ + + + + diff --git a/firetweet.donate.nyanwp.wear/src/main/res/layout/round_activity_nyan.xml b/firetweet.donate.nyanwp.wear/src/main/res/layout/round_activity_nyan.xml new file mode 100644 index 00000000..1b55121a --- /dev/null +++ b/firetweet.donate.nyanwp.wear/src/main/res/layout/round_activity_nyan.xml @@ -0,0 +1,28 @@ + + + + diff --git a/firetweet.donate.nyanwp.wear/src/main/res/values/strings.xml b/firetweet.donate.nyanwp.wear/src/main/res/values/strings.xml new file mode 100644 index 00000000..8e2bd2d4 --- /dev/null +++ b/firetweet.donate.nyanwp.wear/src/main/res/values/strings.xml @@ -0,0 +1,27 @@ + + + + + + firetweet.donate.nyanwp.wear + Hello Round World! + Hello Square World! + + diff --git a/firetweet.donate.nyanwp.wear/web_hi_res_512.png b/firetweet.donate.nyanwp.wear/web_hi_res_512.png new file mode 100755 index 00000000..ccc62926 Binary files /dev/null and b/firetweet.donate.nyanwp.wear/web_hi_res_512.png differ diff --git a/firetweet.donate.nyanwp/.gitignore b/firetweet.donate.nyanwp/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.donate.nyanwp/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.donate.nyanwp/build.gradle b/firetweet.donate.nyanwp/build.gradle new file mode 100644 index 00000000..b98b4b49 --- /dev/null +++ b/firetweet.donate.nyanwp/build.gradle @@ -0,0 +1,42 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.application' +apply from: rootProject.file('global.gradle') +apply from: rootProject.file('signing.gradle') + +android { + defaultConfig { + applicationId "org.getlantern.firetweet.donate.nyanwp" + minSdkVersion 14 + targetSdkVersion 22 + versionCode 3 + versionName "1.2" + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } +} + +dependencies { + wearApp project(':firetweet.donate.nyanwp.wear') + compile project(':firetweet.component.nyan') + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.donate.nyanwp/ic_launcher-web.png b/firetweet.donate.nyanwp/ic_launcher-web.png new file mode 100644 index 00000000..a9b0a840 Binary files /dev/null and b/firetweet.donate.nyanwp/ic_launcher-web.png differ diff --git a/firetweet.donate.nyanwp/proguard-rules.pro b/firetweet.donate.nyanwp/proguard-rules.pro new file mode 100644 index 00000000..ee5b46f0 --- /dev/null +++ b/firetweet.donate.nyanwp/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.donate.nyanwp/src/androidTest/java/org/getlantern/firetweet/donate/nyanwp/ApplicationTest.java b/firetweet.donate.nyanwp/src/androidTest/java/org/getlantern/firetweet/donate/nyanwp/ApplicationTest.java new file mode 100644 index 00000000..06045232 --- /dev/null +++ b/firetweet.donate.nyanwp/src/androidTest/java/org/getlantern/firetweet/donate/nyanwp/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.donate.nyanwp; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.donate.nyanwp/src/main/AndroidManifest.xml b/firetweet.donate.nyanwp/src/main/AndroidManifest.xml new file mode 100644 index 00000000..88911391 --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + diff --git a/firetweet.donate.nyanwp/src/main/res/drawable-hdpi/ic_launcher.png b/firetweet.donate.nyanwp/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 00000000..96a442e5 Binary files /dev/null and b/firetweet.donate.nyanwp/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp/src/main/res/drawable-mdpi/ic_launcher.png b/firetweet.donate.nyanwp/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 00000000..359047df Binary files /dev/null and b/firetweet.donate.nyanwp/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp/src/main/res/drawable-nodpi/nyan_sakamoto_thumbnail_bitmap.png b/firetweet.donate.nyanwp/src/main/res/drawable-nodpi/nyan_sakamoto_thumbnail_bitmap.png new file mode 100644 index 00000000..37dae3fe Binary files /dev/null and b/firetweet.donate.nyanwp/src/main/res/drawable-nodpi/nyan_sakamoto_thumbnail_bitmap.png differ diff --git a/firetweet.donate.nyanwp/src/main/res/drawable-xhdpi/ic_launcher.png b/firetweet.donate.nyanwp/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 00000000..71c6d760 Binary files /dev/null and b/firetweet.donate.nyanwp/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp/src/main/res/drawable-xxhdpi/ic_launcher.png b/firetweet.donate.nyanwp/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..4df18946 Binary files /dev/null and b/firetweet.donate.nyanwp/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/firetweet.donate.nyanwp/src/main/res/drawable/nyan_sakamoto_thumbnail.xml b/firetweet.donate.nyanwp/src/main/res/drawable/nyan_sakamoto_thumbnail.xml new file mode 100644 index 00000000..0b89d80a --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/drawable/nyan_sakamoto_thumbnail.xml @@ -0,0 +1,6 @@ + + diff --git a/firetweet.donate.nyanwp/src/main/res/values-land/integers.xml b/firetweet.donate.nyanwp/src/main/res/values-land/integers.xml new file mode 100644 index 00000000..0ca9c819 --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values-land/integers.xml @@ -0,0 +1,6 @@ + + + 5 + 17 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values-large-land/integers.xml b/firetweet.donate.nyanwp/src/main/res/values-large-land/integers.xml new file mode 100644 index 00000000..6898c9ba --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values-large-land/integers.xml @@ -0,0 +1,6 @@ + + + 8 + 23 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values-large/integers.xml b/firetweet.donate.nyanwp/src/main/res/values-large/integers.xml new file mode 100644 index 00000000..51215f2c --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values-large/integers.xml @@ -0,0 +1,7 @@ + + + 10 + 13 + 2 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values-xlarge-land/integers.xml b/firetweet.donate.nyanwp/src/main/res/values-xlarge-land/integers.xml new file mode 100644 index 00000000..aed0b506 --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values-xlarge-land/integers.xml @@ -0,0 +1,6 @@ + + + 13 + 31 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values-xlarge/integers.xml b/firetweet.donate.nyanwp/src/main/res/values-xlarge/integers.xml new file mode 100644 index 00000000..323e2dae --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values-xlarge/integers.xml @@ -0,0 +1,7 @@ + + + 15 + 19 + 3 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values/colors.xml b/firetweet.donate.nyanwp/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8011db6 --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values/colors.xml @@ -0,0 +1,5 @@ + + + #003366 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values/integers.xml b/firetweet.donate.nyanwp/src/main/res/values/integers.xml new file mode 100644 index 00000000..52745dcd --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values/integers.xml @@ -0,0 +1,7 @@ + + + 8 + 11 + 1 + + diff --git a/firetweet.donate.nyanwp/src/main/res/values/strings.xml b/firetweet.donate.nyanwp/src/main/res/values/strings.xml new file mode 100644 index 00000000..2075de25 --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + Twidere Donate Live Wallpaper + Twidere Donate Wallpaper + Twidere Donate Daydream + + diff --git a/firetweet.donate.nyanwp/src/main/res/values/styles.xml b/firetweet.donate.nyanwp/src/main/res/values/styles.xml new file mode 100644 index 00000000..d98a53a8 --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/values/styles.xml @@ -0,0 +1,21 @@ + + + + diff --git a/firetweet.donate.nyanwp/src/main/res/xml/nyan_wallpaper.xml b/firetweet.donate.nyanwp/src/main/res/xml/nyan_wallpaper.xml new file mode 100644 index 00000000..58df3aab --- /dev/null +++ b/firetweet.donate.nyanwp/src/main/res/xml/nyan_wallpaper.xml @@ -0,0 +1,3 @@ + + diff --git a/firetweet.extension.push.xiaomi/.gitignore b/firetweet.extension.push.xiaomi/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/firetweet.extension.push.xiaomi/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firetweet.extension.push.xiaomi/build.gradle b/firetweet.extension.push.xiaomi/build.gradle new file mode 100644 index 00000000..d55ee217 --- /dev/null +++ b/firetweet.extension.push.xiaomi/build.gradle @@ -0,0 +1,41 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.application' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + applicationId "org.getlantern.firetweet.extension.push.xiaomi" + minSdkVersion 14 + targetSdkVersion 22 + versionCode 2 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/firetweet.extension.push.xiaomi/libs/MiPush_SDK_Client_2_2_13_sdk.jar b/firetweet.extension.push.xiaomi/libs/MiPush_SDK_Client_2_2_13_sdk.jar new file mode 100644 index 00000000..6570b2ab Binary files /dev/null and b/firetweet.extension.push.xiaomi/libs/MiPush_SDK_Client_2_2_13_sdk.jar differ diff --git a/firetweet.extension.push.xiaomi/proguard-rules.pro b/firetweet.extension.push.xiaomi/proguard-rules.pro new file mode 100644 index 00000000..a3abb5fc --- /dev/null +++ b/firetweet.extension.push.xiaomi/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/firetweet.extension.push.xiaomi/src/androidTest/java/org/getlantern/firetweet/extension/push/xiaomi/ApplicationTest.java b/firetweet.extension.push.xiaomi/src/androidTest/java/org/getlantern/firetweet/extension/push/xiaomi/ApplicationTest.java new file mode 100644 index 00000000..1a462325 --- /dev/null +++ b/firetweet.extension.push.xiaomi/src/androidTest/java/org/getlantern/firetweet/extension/push/xiaomi/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.getlantern.firetweet.extension.push.xiaomi; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} diff --git a/firetweet.extension.push.xiaomi/src/main/AndroidManifest.xml b/firetweet.extension.push.xiaomi/src/main/AndroidManifest.xml new file mode 100644 index 00000000..b0b1d33d --- /dev/null +++ b/firetweet.extension.push.xiaomi/src/main/AndroidManifest.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/DemoApplication.java b/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/DemoApplication.java new file mode 100644 index 00000000..612165cd --- /dev/null +++ b/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/DemoApplication.java @@ -0,0 +1,76 @@ +package org.getlantern.firetweet.extension.push.xiaomi; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.Application; +import android.content.Context; +import android.os.Process; +import android.util.Log; + +import com.xiaomi.channel.commonutils.logger.LoggerInterface; +import com.xiaomi.mipush.sdk.Logger; +import com.xiaomi.mipush.sdk.MiPushClient; + +import java.util.List; + +/** + * 1、为了打开客户端的日志,便于在开发过程中调试,需要自定义一个Application。 + * 并将自定义的application注册在AndroidManifest.xml文件中 + * 2、为了提高push的注册率,您可以在Application的onCreate中初始化push。你也可以根据需要,在其他地方初始化push。 + * + * @author wangkuiwei + */ +public class DemoApplication extends Application { + + // user your appid the key. + public static final String APP_ID = "2882303761517305779"; + // user your appid the key. + public static final String APP_KEY = "5311730548779"; + + // 此TAG在adb logcat中检索自己所需要的信息, 只需在命令行终端输入 adb logcat | grep + // com.xiaomi.mipushdemo + public static final String TAG = BuildConfig.APPLICATION_ID; + + @Override + public void onCreate() { + super.onCreate(); + // 注册push服务,注册成功后会向DemoMessageReceiver发送广播 + // 可以从DemoMessageReceiver的onCommandResult方法中MiPushCommandMessage对象参数中获取注册信息 + if (shouldInit()) { + MiPushClient.registerPush(this, APP_ID, APP_KEY); + } + + LoggerInterface newLogger = new LoggerInterface() { + + @Override + public void setTag(String tag) { + // ignore + } + + @Override + public void log(String content, Throwable t) { + Log.d(TAG, content, t); + } + + @Override + public void log(String content) { + Log.d(TAG, content); + } + }; + Logger.setLogger(this, newLogger); + } + + private boolean shouldInit() { + ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)); + List processInfos = am.getRunningAppProcesses(); + String mainProcessName = getPackageName(); + int myPid = Process.myPid(); + for (RunningAppProcessInfo info : processInfos) { + if (info.pid == myPid && mainProcessName.equals(info.processName)) { + return true; + } + } + return false; + } + +} diff --git a/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/DemoMessageReceiver.java b/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/DemoMessageReceiver.java new file mode 100644 index 00000000..52252740 --- /dev/null +++ b/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/DemoMessageReceiver.java @@ -0,0 +1,52 @@ +package org.getlantern.firetweet.extension.push.xiaomi; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Message; +import android.util.Log; + +import com.xiaomi.mipush.sdk.MiPushCommandMessage; +import com.xiaomi.mipush.sdk.MiPushMessage; +import com.xiaomi.mipush.sdk.PushMessageReceiver; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 1、PushMessageReceiver是个抽象类,该类继承了BroadcastReceiver。 + * 2、需要将自定义的DemoMessageReceiver注册在AndroidManifest.xml文件中 + * + * + * + * 3、DemoMessageReceiver的onCommandResult方法用来接收客户端向服务器发送命令后的响应结果 + * 4、DemoMessageReceiver的onReceiveMessage方法用来接收服务器向客户端发送的消息 + * 5、onReceiveMessage和onCommandResult方法运行在非UI线程中 + * + * @author wangkuiwei + */ +public class DemoMessageReceiver extends PushMessageReceiver { + + @Override + public void onReceiveMessage(Context context, MiPushMessage message) { + Log.v(DemoApplication.TAG, + "onReceiveMessage is called. " + message.toString()); + String log = context.getString(R.string.recv_message, message.getContent()); + + Message msg = Message.obtain(); + if (message.isNotified()) { + msg.obj = log; + } + } + + @Override + public void onCommandResult(Context context, MiPushCommandMessage message) { + } + + @SuppressLint("SimpleDateFormat") + public static String getSimpleDate() { + return new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()); + } + +} diff --git a/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/MainActivity.java b/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/MainActivity.java new file mode 100644 index 00000000..a6ddb119 --- /dev/null +++ b/firetweet.extension.push.xiaomi/src/main/java/org/getlantern/firetweet/extension/push/xiaomi/MainActivity.java @@ -0,0 +1,7 @@ +package org.getlantern.firetweet.extension.push.xiaomi; + +import android.app.Activity; + +public class MainActivity extends Activity { + +} diff --git a/firetweet.extension.push.xiaomi/src/main/res/drawable-hdpi/ic_custom_notify.png b/firetweet.extension.push.xiaomi/src/main/res/drawable-hdpi/ic_custom_notify.png new file mode 100644 index 00000000..b1d5aced Binary files /dev/null and b/firetweet.extension.push.xiaomi/src/main/res/drawable-hdpi/ic_custom_notify.png differ diff --git a/firetweet.extension.push.xiaomi/src/main/res/drawable-hdpi/ic_launcher.png b/firetweet.extension.push.xiaomi/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 00000000..288b6655 Binary files /dev/null and b/firetweet.extension.push.xiaomi/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/firetweet.extension.push.xiaomi/src/main/res/drawable-mdpi/ic_launcher.png b/firetweet.extension.push.xiaomi/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 00000000..6ae570b4 Binary files /dev/null and b/firetweet.extension.push.xiaomi/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/firetweet.extension.push.xiaomi/src/main/res/drawable-xhdpi/ic_launcher.png b/firetweet.extension.push.xiaomi/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 00000000..d4fb7cd9 Binary files /dev/null and b/firetweet.extension.push.xiaomi/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/firetweet.extension.push.xiaomi/src/main/res/drawable-xhdpi/ic_tip.png b/firetweet.extension.push.xiaomi/src/main/res/drawable-xhdpi/ic_tip.png new file mode 100644 index 00000000..6793fb57 Binary files /dev/null and b/firetweet.extension.push.xiaomi/src/main/res/drawable-xhdpi/ic_tip.png differ diff --git a/firetweet.extension.push.xiaomi/src/main/res/drawable-xxhdpi/ic_launcher.png b/firetweet.extension.push.xiaomi/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..85a60815 Binary files /dev/null and b/firetweet.extension.push.xiaomi/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/firetweet.extension.push.xiaomi/src/main/res/layout/activity_main.xml b/firetweet.extension.push.xiaomi/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..f21eb942 --- /dev/null +++ b/firetweet.extension.push.xiaomi/src/main/res/layout/activity_main.xml @@ -0,0 +1,177 @@ + + + + + + + + +