From 57f94e29787bf4384f4322bef8a5d1576857f7ca Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Thu, 28 May 2015 00:31:48 +0800 Subject: [PATCH] redesigning dashboard --- global.gradle | 11 + settings.gradle | 1 - twidere.component.common/build.gradle | 1 - .../constant/SharedPreferenceConstants.java | 2 + .../twidere/model/ParcelableUserMention.java | 23 +- .../twidere/util/TwitterAPIUtils.java | 279 ---------------- twidere.extension.streaming/.gitignore | 1 - twidere.extension.streaming/build.gradle | 58 ---- .../proguard-rules.pro | 17 - .../src/main/AndroidManifest.xml | 37 --- .../extension/streaming/Constants.java | 12 - .../extension/streaming/PrivateConstants.java | 10 - .../extension/streaming/SettingsActivity.java | 69 ---- .../streaming/TwidereLaunchReceiver.java | 22 -- .../streaming/util/ActivityAccessor.java | 70 ---- .../streaming/util/OkHttpRestClient.java | 197 ------------ .../util/TwidereHostAddressResolver.java | 82 ----- .../extension/streaming/util/Utils.java | 144 --------- .../res/drawable-hdpi-v11/ic_stat_login.png | Bin 764 -> 0 bytes .../res/drawable-hdpi-v11/ic_stat_twidere.png | Bin 885 -> 0 bytes .../res/drawable-hdpi-v9/ic_stat_login.png | Bin 783 -> 0 bytes .../res/drawable-hdpi-v9/ic_stat_twidere.png | Bin 791 -> 0 bytes .../main/res/drawable-hdpi/ic_launcher.png | Bin 3726 -> 0 bytes .../main/res/drawable-hdpi/ic_stat_login.png | Bin 1301 -> 0 bytes .../res/drawable-hdpi/ic_stat_twidere.png | Bin 1277 -> 0 bytes .../res/drawable-ldpi-v11/ic_stat_login.png | Bin 402 -> 0 bytes .../res/drawable-ldpi-v11/ic_stat_twidere.png | Bin 418 -> 0 bytes .../res/drawable-ldpi-v9/ic_stat_login.png | Bin 392 -> 0 bytes .../res/drawable-ldpi-v9/ic_stat_twidere.png | Bin 375 -> 0 bytes .../res/drawable-mdpi-v11/ic_stat_login.png | Bin 463 -> 0 bytes .../res/drawable-mdpi-v11/ic_stat_twidere.png | Bin 563 -> 0 bytes .../res/drawable-mdpi-v9/ic_stat_login.png | Bin 529 -> 0 bytes .../res/drawable-mdpi-v9/ic_stat_twidere.png | Bin 490 -> 0 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 2147 -> 0 bytes .../main/res/drawable-mdpi/ic_stat_login.png | Bin 869 -> 0 bytes .../res/drawable-mdpi/ic_stat_twidere.png | Bin 848 -> 0 bytes .../res/drawable-xhdpi-v11/ic_stat_login.png | Bin 918 -> 0 bytes .../drawable-xhdpi-v11/ic_stat_twidere.png | Bin 1324 -> 0 bytes .../res/drawable-xhdpi-v9/ic_stat_login.png | Bin 1010 -> 0 bytes .../res/drawable-xhdpi-v9/ic_stat_twidere.png | Bin 1053 -> 0 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 5659 -> 0 bytes .../main/res/drawable-xhdpi/ic_stat_login.png | Bin 1829 -> 0 bytes .../res/drawable-xhdpi/ic_stat_twidere.png | Bin 1876 -> 0 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 10713 -> 0 bytes .../src/main/res/values-hdpi/bools.xml | 6 - .../src/main/res/values/bools.xml | 6 - .../src/main/res/values/strings.xml | 9 - .../src/main/res/xml/settings.xml | 9 - twidere/build.gradle | 13 +- .../twidere/util/DebugModeUtils.java | 43 +++ twidere/src/main/AndroidManifest.xml | 301 +++++++++--------- .../edu/ucdavis/earlybird/CSVFileFilter.java | 19 -- .../edu/ucdavis/earlybird/ProfilingUtil.java | 70 ---- .../edu/ucdavis/earlybird/UCDService.java | 42 --- .../edu/ucdavis/earlybird/UploadReceiver.java | 27 -- .../edu/ucdavis/earlybird/UploadTask.java | 146 --------- .../support/BrowserSignInActivity.java | 3 +- .../activity/support/HomeActivity.java | 11 +- .../activity/support/SignInActivity.java | 17 +- .../api/twitter/TwitterUserStream.java | 0 .../api/twitter/UserStreamCallback.java | 153 +++++---- .../api/twitter/util/CRLFLineReader.java | 0 .../api/twitter/util/JSONObjectType.java | 0 .../twidere/app/TwidereApplication.java | 8 +- .../AccountRefreshSettingsFragment.java | 5 +- .../BaseAccountPreferenceFragment.java | 18 +- .../support/AccountsDashboardFragment.java | 62 ++-- .../support/DirectMessagesFragment.java | 11 + .../support/HomeTimelineFragment.java | 14 + .../support/MentionsTimelineFragment.java | 12 + .../twidere/model/AccountPreferences.java | 4 + .../preference/AccountsListPreference.java | 59 +--- .../preference/AutoFixSwitchPreference.java | 2 - .../DarkLightThemeTogglePreference.java | 55 ++++ .../twidere/service}/StreamingService.java | 199 +++++++----- .../twidere/util/AsyncTwitterWrapper.java | 3 - .../twidere/util/OnLinkClickHandler.java | 3 - .../mariotaku/twidere/util/ThemeUtils.java | 4 + .../twidere/util/TwitterAPIFactory.java | 254 ++++++++++++++- .../org/mariotaku/twidere/util/Utils.java | 4 - .../imageloader/TwidereImageDownloader.java | 5 +- .../twidere/util/net/OkHttpRestClient.java | 2 + .../layout/action_item_space.xml | 24 ++ .../drawable-hdpi/ic_stat_refresh.png | Bin 0 -> 718 bytes .../drawable-mdpi/ic_stat_refresh.png | Bin 0 -> 510 bytes .../drawable-xhdpi/ic_stat_refresh.png | Bin 0 -> 853 bytes .../drawable-xxhdpi/ic_stat_refresh.png | Bin 0 -> 1158 bytes .../drawable-xxxhdpi/ic_stat_refresh.png | Bin 0 -> 1499 bytes .../layout/fragment_accounts_dashboard.xml | 27 +- .../res/layout/list_item_dashboard_menu.xml | 52 +++ .../src/main/res/layout/list_item_menu.xml | 2 +- twidere/src/main/res/menu/menu_dashboard.xml | 54 ++++ twidere/src/main/res/values/strings.xml | 5 + .../res/xml/preferences_account_refresh.xml | 17 + .../res/xml/preferences_notifications.xml | 6 - .../src/main/res/xml/preferences_theme.xml | 23 +- .../src/main/svg-png/ic_stat_refresh-mdpi.svg | 4 + .../twidere/util/DebugModeUtils.java | 24 +- 98 files changed, 1062 insertions(+), 1811 deletions(-) delete mode 100644 twidere.component.common/src/main/java/org/mariotaku/twidere/util/TwitterAPIUtils.java delete mode 100644 twidere.extension.streaming/.gitignore delete mode 100644 twidere.extension.streaming/build.gradle delete mode 100644 twidere.extension.streaming/proguard-rules.pro delete mode 100644 twidere.extension.streaming/src/main/AndroidManifest.xml delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/Constants.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/PrivateConstants.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/SettingsActivity.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/TwidereLaunchReceiver.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/ActivityAccessor.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/OkHttpRestClient.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/TwidereHostAddressResolver.java delete mode 100644 twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/Utils.java delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi-v11/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi-v11/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi-v9/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi-v9/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi/ic_launcher.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-hdpi/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-ldpi-v11/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-ldpi-v11/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-ldpi-v9/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-ldpi-v9/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi-v11/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi-v11/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi-v9/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi-v9/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi/ic_launcher.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-mdpi/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi-v11/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi-v11/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi-v9/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi-v9/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi/ic_launcher.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi/ic_stat_login.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xhdpi/ic_stat_twidere.png delete mode 100644 twidere.extension.streaming/src/main/res/drawable-xxhdpi/ic_launcher.png delete mode 100644 twidere.extension.streaming/src/main/res/values-hdpi/bools.xml delete mode 100644 twidere.extension.streaming/src/main/res/values/bools.xml delete mode 100644 twidere.extension.streaming/src/main/res/values/strings.xml delete mode 100644 twidere.extension.streaming/src/main/res/xml/settings.xml create mode 100644 twidere/src/debug/java/org/mariotaku/twidere/util/DebugModeUtils.java delete mode 100644 twidere/src/main/java/edu/ucdavis/earlybird/CSVFileFilter.java delete mode 100644 twidere/src/main/java/edu/ucdavis/earlybird/ProfilingUtil.java delete mode 100644 twidere/src/main/java/edu/ucdavis/earlybird/UCDService.java delete mode 100644 twidere/src/main/java/edu/ucdavis/earlybird/UploadReceiver.java delete mode 100644 twidere/src/main/java/edu/ucdavis/earlybird/UploadTask.java rename {twidere.component.common => twidere}/src/main/java/org/mariotaku/twidere/api/twitter/TwitterUserStream.java (100%) rename {twidere.component.common => twidere}/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java (57%) rename {twidere.component.common => twidere}/src/main/java/org/mariotaku/twidere/api/twitter/util/CRLFLineReader.java (100%) rename {twidere.component.common => twidere}/src/main/java/org/mariotaku/twidere/api/twitter/util/JSONObjectType.java (100%) create mode 100644 twidere/src/main/java/org/mariotaku/twidere/preference/DarkLightThemeTogglePreference.java rename {twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming => twidere/src/main/java/org/mariotaku/twidere/service}/StreamingService.java (68%) create mode 100644 twidere/src/main/res-localized/layout/action_item_space.xml create mode 100644 twidere/src/main/res-svg2png/drawable-hdpi/ic_stat_refresh.png create mode 100644 twidere/src/main/res-svg2png/drawable-mdpi/ic_stat_refresh.png create mode 100644 twidere/src/main/res-svg2png/drawable-xhdpi/ic_stat_refresh.png create mode 100644 twidere/src/main/res-svg2png/drawable-xxhdpi/ic_stat_refresh.png create mode 100644 twidere/src/main/res-svg2png/drawable-xxxhdpi/ic_stat_refresh.png create mode 100644 twidere/src/main/res/layout/list_item_dashboard_menu.xml create mode 100644 twidere/src/main/res/menu/menu_dashboard.xml create mode 100644 twidere/src/main/svg-png/ic_stat_refresh-mdpi.svg rename twidere.extension.streaming/src/androidTest/java/org/mariotaku/twidere/extension/streaming/ApplicationTest.java => twidere/src/release/java/org/mariotaku/twidere/util/DebugModeUtils.java (66%) diff --git a/global.gradle b/global.gradle index 9ce8a3d44..feeba163e 100644 --- a/global.gradle +++ b/global.gradle @@ -23,4 +23,15 @@ android { lintOptions { abortOnError false } + + packagingOptions { + exclude 'META-INF/DEPENDENCIES' + exclude 'META-INF/LICENSE' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/notice.txt' + exclude 'META-INF/ASL2.0' + } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 405d6e9b2..8850e4395 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,5 @@ include ':twidere.donate.nyanwp' include ':twidere.donate.nyanwp.wear' include ':twidere.component.nyan' include ':twidere.extension.twitlonger' -include ':twidere.extension.streaming' include ':twidere.extension.push.xiaomi' include ':twidere.extension.launcher.compose' \ No newline at end of file diff --git a/twidere.component.common/build.gradle b/twidere.component.common/build.gradle index fd3059a10..41c053e6e 100644 --- a/twidere.component.common/build.gradle +++ b/twidere.component.common/build.gradle @@ -45,7 +45,6 @@ dependencies { compile 'org.apache.commons:commons-lang3:3.4' compile 'com.github.mariotaku:RestFu:6ef0913' compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1' - compile 'com.fasterxml.jackson.core:jackson-databind:2.4.4' compile project(':twidere.component.querybuilder') compile fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java index 4ee094f56..36f609c3a 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/constant/SharedPreferenceConstants.java @@ -189,6 +189,8 @@ public interface SharedPreferenceConstants { String KEY_MENTIONS_NOTIFICATION = "mentions_notification"; @Preference(type = BOOLEAN) String KEY_DIRECT_MESSAGES_NOTIFICATION = "direct_messages_notification"; + @Preference(type = BOOLEAN) + String KEY_ENABLE_STREAMING = "enable_streaming"; @Preference(type = INT) String KEY_LOCAL_TRENDS_WOEID = "local_trends_woeid"; String KEY_NOTIFICATION_RINGTONE = "notification_ringtone"; diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableUserMention.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableUserMention.java index d782dd852..0c154b4cd 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableUserMention.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableUserMention.java @@ -26,14 +26,17 @@ import android.text.TextUtils; import com.bluelinelabs.logansquare.LoganSquare; import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonObject; - -import java.io.IOException; -import java.util.List; +import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease; +import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease; import org.mariotaku.twidere.api.twitter.model.Status; import org.mariotaku.twidere.api.twitter.model.UserMentionEntity; +import java.io.IOException; +import java.util.List; + @JsonObject +@ParcelablePlease(allFields = false) public class ParcelableUserMention implements Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -48,10 +51,13 @@ public class ParcelableUserMention implements Parcelable { } }; + @ParcelableThisPlease @JsonField(name = "id") public long id; + @ParcelableThisPlease @JsonField(name = "name") public String name; + @ParcelableThisPlease @JsonField(name = "screen_name") public String screen_name; @@ -87,8 +93,15 @@ public class ParcelableUserMention implements Parcelable { } public static ParcelableUserMention[] fromSerializedJson(String string) { - - return new ParcelableUserMention[0]; + if (string == null) return null; + final List list; + try { + list = LoganSquare.parseList(string, ParcelableUserMention.class); + } catch (IOException e) { + return null; + } + if (list == null) return null; + return list.toArray(new ParcelableUserMention[list.size()]); } @Override diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/util/TwitterAPIUtils.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/util/TwitterAPIUtils.java deleted file mode 100644 index aab082f89..000000000 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/util/TwitterAPIUtils.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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.mariotaku.twidere.util; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.util.Pair; - -import org.mariotaku.restfu.ExceptionFactory; -import org.mariotaku.restfu.HttpRequestFactory; -import org.mariotaku.restfu.RequestInfoFactory; -import org.mariotaku.restfu.RestMethodInfo; -import org.mariotaku.restfu.RestRequestInfo; -import org.mariotaku.restfu.annotation.RestMethod; -import org.mariotaku.restfu.http.Authorization; -import org.mariotaku.restfu.http.Endpoint; -import org.mariotaku.restfu.http.FileValue; -import org.mariotaku.restfu.http.RestHttpRequest; -import org.mariotaku.restfu.http.RestHttpResponse; -import org.mariotaku.restfu.http.mime.StringTypedData; -import org.mariotaku.restfu.http.mime.TypedData; -import org.mariotaku.twidere.TwidereConstants; -import org.mariotaku.twidere.api.twitter.Twitter; -import org.mariotaku.twidere.api.twitter.TwitterException; -import org.mariotaku.twidere.api.twitter.TwitterOAuth; -import org.mariotaku.twidere.api.twitter.TwitterUpload; -import org.mariotaku.twidere.api.twitter.TwitterUserStream; -import org.mariotaku.twidere.api.twitter.auth.BasicAuthorization; -import org.mariotaku.twidere.api.twitter.auth.EmptyAuthorization; -import org.mariotaku.twidere.api.twitter.auth.OAuthAuthorization; -import org.mariotaku.twidere.api.twitter.auth.OAuthEndpoint; -import org.mariotaku.twidere.api.twitter.auth.OAuthToken; -import org.mariotaku.twidere.api.twitter.util.TwitterConverter; -import org.mariotaku.twidere.model.ConsumerKeyType; -import org.mariotaku.twidere.model.ParcelableCredentials; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static android.text.TextUtils.isEmpty; - -/** - * Created by mariotaku on 15/5/26. - */ -public class TwitterAPIUtils implements TwidereConstants { - - public static Endpoint getEndpoint(ParcelableCredentials credentials, Class cls) { - final String apiUrlFormat; - final boolean sameOAuthSigningUrl = credentials.same_oauth_signing_url; - final boolean noVersionSuffix = credentials.no_version_suffix; - if (!isEmpty(credentials.api_url_format)) { - apiUrlFormat = credentials.api_url_format; - } else { - apiUrlFormat = DEFAULT_TWITTER_API_URL_FORMAT; - } - final String domain, versionSuffix; - if (Twitter.class.isAssignableFrom(cls)) { - domain = "api"; - versionSuffix = noVersionSuffix ? null : "/1.1/"; - } else if (TwitterUpload.class.isAssignableFrom(cls)) { - domain = "upload"; - versionSuffix = noVersionSuffix ? null : "/1.1/"; - } else if (TwitterOAuth.class.isAssignableFrom(cls)) { - domain = "api"; - versionSuffix = "oauth"; - } else if (TwitterUserStream.class.isAssignableFrom(cls)) { - domain = "userstream"; - versionSuffix = noVersionSuffix ? null : "/1.1/"; - } else { - throw new TwitterConverter.UnsupportedTypeException(cls); - } - final String endpointUrl; - endpointUrl = getApiUrl(apiUrlFormat, domain, versionSuffix); - if (credentials.auth_type == ParcelableCredentials.AUTH_TYPE_XAUTH || credentials.auth_type == ParcelableCredentials.AUTH_TYPE_OAUTH) { - final String signEndpointUrl; - if (!sameOAuthSigningUrl) { - signEndpointUrl = getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, domain, versionSuffix); - } else { - signEndpointUrl = endpointUrl; - } - return new OAuthEndpoint(endpointUrl, signEndpointUrl); - } - return new Endpoint(endpointUrl); - } - - public static Authorization getAuthorization(ParcelableCredentials credentials) { - switch (credentials.auth_type) { - case ParcelableCredentials.AUTH_TYPE_OAUTH: - case ParcelableCredentials.AUTH_TYPE_XAUTH: { - final String consumerKey = TextUtils.isEmpty(credentials.consumer_key) ? - TWITTER_CONSUMER_KEY_LEGACY : credentials.consumer_key; - final String consumerSecret = TextUtils.isEmpty(credentials.consumer_secret) ? - TWITTER_CONSUMER_SECRET_LEGACY : credentials.consumer_secret; - final OAuthToken accessToken = new OAuthToken(credentials.oauth_token, credentials.oauth_token_secret); - return new OAuthAuthorization(consumerKey, consumerSecret, accessToken); - } - case ParcelableCredentials.AUTH_TYPE_BASIC: { - final String screenName = credentials.screen_name; - final String username = credentials.basic_auth_username; - final String loginName = username != null ? username : screenName; - final String password = credentials.basic_auth_password; - if (isEmpty(loginName) || isEmpty(password)) return null; - return new BasicAuthorization(loginName, password); - } - } - return new EmptyAuthorization(); - } - - private static void addParameter(List> params, String name, Object value) { - params.add(Pair.create(name, String.valueOf(value))); - } - - private static void addPart(List> params, String name, Object value) { - final TypedData typedData = new StringTypedData(String.valueOf(value), Charset.defaultCharset()); - params.add(Pair.create(name, typedData)); - } - - public static String getApiBaseUrl(String format, final String domain) { - if (format == null) return null; - final Matcher matcher = Pattern.compile("\\[(\\.?)DOMAIN(\\.?)\\]").matcher(format); - if (!matcher.find()) { - // For backward compatibility - format = substituteLegacyApiBaseUrl(format, domain); - if (!format.endsWith("/1.1") && !format.endsWith("/1.1/")) { - return format; - } - final String versionSuffix = "/1.1"; - final int suffixLength = versionSuffix.length(); - final int lastIndex = format.lastIndexOf(versionSuffix); - return format.substring(0, lastIndex) + format.substring(lastIndex + suffixLength); - } - if (TextUtils.isEmpty(domain)) return matcher.replaceAll(""); - return matcher.replaceAll(String.format("$1%s$2", domain)); - } - - private static String substituteLegacyApiBaseUrl(@NonNull String format, String domain) { - final int startOfHost = format.indexOf("://") + 3, endOfHost = format.indexOf('/', startOfHost); - final String host = endOfHost != -1 ? format.substring(startOfHost, endOfHost) : format.substring(startOfHost); - if (!host.equalsIgnoreCase("api.twitter.com")) return format; - return format.substring(0, startOfHost) + domain + ".twitter.com" + format.substring(endOfHost); - } - - public static String getApiUrl(final String pattern, final String domain, final String appendPath) { - final String urlBase = getApiBaseUrl(pattern, domain); - if (urlBase == null) return null; - if (appendPath == null) return urlBase.endsWith("/") ? urlBase : urlBase + "/"; - final StringBuilder sb = new StringBuilder(urlBase); - if (urlBase.endsWith("/")) { - sb.append(appendPath.startsWith("/") ? appendPath.substring(1) : appendPath); - } else { - if (appendPath.startsWith("/")) { - sb.append(appendPath); - } else { - sb.append('/'); - sb.append(appendPath); - } - } - return sb.toString(); - } - - public static String getUserAgentName(ConsumerKeyType type) { - switch (type) { - case TWITTER_FOR_ANDROID: { - return "TwitterAndroid"; - } - case TWITTER_FOR_IPHONE: { - return "Twitter-iPhone"; - } - case TWITTER_FOR_IPAD: { - return "Twitter-iPad"; - } - case TWITTER_FOR_MAC: { - return "Twitter-Mac"; - } - } - return "Twitter"; - } - - public static String getTwidereUserAgent(final Context context) { - final PackageManager pm = context.getPackageManager(); - try { - final PackageInfo pi = pm.getPackageInfo(TWIDERE_PACKAGE_NAME, 0); - return TWIDERE_APP_NAME + " " + TWIDERE_PROJECT_URL + " / " + pi.versionName; - } catch (final PackageManager.NameNotFoundException e) { - return TWIDERE_APP_NAME + " " + TWIDERE_PROJECT_URL; - } - } - - public static class TwidereRequestInfoFactory implements RequestInfoFactory { - @Override - public RestRequestInfo create(RestMethodInfo methodInfo) { - final RestMethod method = methodInfo.getMethod(); - final String path = methodInfo.getPath(); - final List> queries = new ArrayList<>(methodInfo.getQueries()); - final List> forms = new ArrayList<>(methodInfo.getForms()); - final List> headers = methodInfo.getHeaders(); - final List> parts = methodInfo.getParts(); - final FileValue file = methodInfo.getFile(); - final Map extras = methodInfo.getExtras(); - if (parts.isEmpty()) { - final List> params = method.hasBody() ? forms : queries; - addParameter(params, "include_cards", true); - addParameter(params, "cards_platform", "Android-12"); - addParameter(params, "include_entities", true); - addParameter(params, "include_my_retweet", 1); - addParameter(params, "include_rts", 1); - addParameter(params, "include_reply_count", true); - addParameter(params, "include_descendent_reply_count", true); - } else { - addPart(parts, "include_cards", true); - addPart(parts, "cards_platform", "Android-12"); - addPart(parts, "include_entities", true); - addPart(parts, "include_my_retweet", 1); - addPart(parts, "include_rts", 1); - addPart(parts, "include_reply_count", true); - addPart(parts, "include_descendent_reply_count", true); - } - return new RestRequestInfo(method.value(), path, queries, forms, headers, parts, file, - methodInfo.getBody(), extras); - } - } - - public static class TwidereHttpRequestFactory implements HttpRequestFactory { - - private final String userAgent; - - public TwidereHttpRequestFactory(final String userAgent) { - this.userAgent = userAgent; - } - - @Override - public RestHttpRequest create(@NonNull Endpoint endpoint, @NonNull RestRequestInfo info, - @Nullable Authorization authorization) { - final String restMethod = info.getMethod(); - final String url = Endpoint.constructUrl(endpoint.getUrl(), info); - final ArrayList> headers = new ArrayList<>(info.getHeaders()); - - if (authorization != null && authorization.hasAuthorization()) { - headers.add(Pair.create("Authorization", authorization.getHeader(endpoint, info))); - } - headers.add(Pair.create("User-Agent", userAgent)); - return new RestHttpRequest(restMethod, url, headers, info.getBody(), null); - } - } - - public static class TwidereExceptionFactory implements ExceptionFactory { - @Override - public Exception newException(Throwable cause, RestHttpRequest request, RestHttpResponse response) { - final TwitterException te = new TwitterException(cause); - te.setResponse(response); - return te; - } - } -} diff --git a/twidere.extension.streaming/.gitignore b/twidere.extension.streaming/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/twidere.extension.streaming/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/twidere.extension.streaming/build.gradle b/twidere.extension.streaming/build.gradle deleted file mode 100644 index 003774997..000000000 --- a/twidere.extension.streaming/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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') -apply from: rootProject.file('signing.gradle') - -android { - defaultConfig { - applicationId "org.mariotaku.twidere.extension.streaming" - minSdkVersion 14 - targetSdkVersion 22 - versionCode 14 - versionName "1.12 (0.3.0-dev)" - } - packagingOptions { - exclude 'META-INF/DEPENDENCIES' - exclude 'META-INF/LICENSE' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/license.txt' - exclude 'META-INF/NOTICE' - exclude 'META-INF/NOTICE.txt' - exclude 'META-INF/notice.txt' - exclude 'META-INF/ASL2.0' - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } -} - -dependencies { - compile 'com.squareup.okhttp:okhttp:2.4.0' - compile project(':twidere.library.extension') - compile fileTree(dir: 'libs', include: ['*.jar']) -} diff --git a/twidere.extension.streaming/proguard-rules.pro b/twidere.extension.streaming/proguard-rules.pro deleted file mode 100644 index ee5b46f04..000000000 --- a/twidere.extension.streaming/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# 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/twidere.extension.streaming/src/main/AndroidManifest.xml b/twidere.extension.streaming/src/main/AndroidManifest.xml deleted file mode 100644 index 41c9021c6..000000000 --- a/twidere.extension.streaming/src/main/AndroidManifest.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/Constants.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/Constants.java deleted file mode 100644 index 49d5a4135..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/Constants.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.mariotaku.twidere.extension.streaming; - -import org.mariotaku.twidere.TwidereConstants; - -public interface Constants extends TwidereConstants { - - public static final String LOGTAG = "Twidere.Streaming"; - - public static final String PREFERENCE_KEY_ACCOUNT_IDS = "account_ids"; - public static final String PREFERENCE_KEY_ENABLE_STREAMING = "enable_streaming"; - -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/PrivateConstants.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/PrivateConstants.java deleted file mode 100644 index 02e0a8c29..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/PrivateConstants.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.mariotaku.twidere.extension.streaming; - -public interface PrivateConstants { - - public static final String TWITTER_CONSUMER_KEY = "uAFVpMhBntJutfVj6abfA"; - public static final String TWITTER_CONSUMER_SECRET = "JARXkJTfxo0F8MyctYy9bUmrLISjo8vXAHsZHYuk2E"; - - public static final String MAPS_API_KEY_RELEASE = "0kjPwJOe_zwYjzGc9uYak7vhm_Sf3eob-2L3Xzw"; - public static final String MAPS_API_KEY_DEBUG = "0kjPwJOe_zwY9p6kT-kygu4mxwysyOOpfkaXqTA"; -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/SettingsActivity.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/SettingsActivity.java deleted file mode 100644 index d68626520..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/SettingsActivity.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.mariotaku.twidere.extension.streaming; - -import org.mariotaku.twidere.Twidere; - -import android.content.ActivityNotFoundException; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.preference.PreferenceManager; - -public class SettingsActivity extends PreferenceActivity implements Constants, OnSharedPreferenceChangeListener { - - private static final int REQUEST_REQUEST_PERMISSIONS = 101; - private SharedPreferences mPreferences; - - @Override - public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) { - if (PREFERENCE_KEY_ENABLE_STREAMING.equals(key)) { - final Intent intent = new Intent(this, StreamingService.class); - if (preferences.getBoolean(key, true)) { - startService(intent); - } else { - stopService(intent); - } - } - } - - @Override - protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { - switch (requestCode) { - case REQUEST_REQUEST_PERMISSIONS: { - if (resultCode != RESULT_OK) { - finish(); - return; - } - } - } - super.onActivityResult(requestCode, resultCode, data); - } - - @SuppressWarnings("deprecation") - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final boolean granted; - try { - granted = Twidere.isPermissionGranted(this); - } catch (final SecurityException e) { - // TODO show error - finish(); - return; - } - if (!granted) { - final Intent intent = new Intent(Twidere.INTENT_ACTION_REQUEST_PERMISSIONS); - intent.setPackage("org.mariotaku.twidere"); - try { - startActivityForResult(intent, REQUEST_REQUEST_PERMISSIONS); - } catch (final ActivityNotFoundException e) { - - } - } - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); - addPreferencesFromResource(R.xml.settings); - mPreferences.registerOnSharedPreferenceChangeListener(this); - } - -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/TwidereLaunchReceiver.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/TwidereLaunchReceiver.java deleted file mode 100644 index b7bdcc8ac..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/TwidereLaunchReceiver.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.mariotaku.twidere.extension.streaming; - -import org.mariotaku.twidere.Twidere; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -public class TwidereLaunchReceiver extends BroadcastReceiver { - - @Override - public void onReceive(final Context context, final Intent intent) { - final String action = intent.getAction(); - final Intent service_intent = new Intent(context, StreamingService.class); - if (Twidere.BROADCAST_HOME_ACTIVITY_ONCREATE.equals(action)) { - context.startService(service_intent); - } else if (Twidere.BROADCAST_HOME_ACTIVITY_ONDESTROY.equals(action)) { - context.stopService(service_intent); - } - } - -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/ActivityAccessor.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/ActivityAccessor.java deleted file mode 100644 index 6bfd747cb..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/ActivityAccessor.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.mariotaku.twidere.extension.streaming.util; - -import android.annotation.TargetApi; -import android.app.ActionBar; -import android.app.Activity; -import android.os.Build; - -public final class ActivityAccessor { - - public static void onBackPressed(final Activity activity) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ECLAIR) return; - OnBackPressedAccessor.onBackPressed(activity); - } - - public static void overridePendingTransition(final Activity activity, final int enter_anim, final int exit_anim) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ECLAIR) return; - OverridePendingTransitionAccessor.overridePendingTransition(activity, enter_anim, exit_anim); - } - - public static void setHomeButtonEnabled(final Activity activity, final boolean enabled) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) return; - SetHomeButtonEnabledAccessor.setHomeButtonEnabled(activity, enabled); - } - - @TargetApi(Build.VERSION_CODES.ECLAIR) - private static class OnBackPressedAccessor { - - private static void onBackPressed(final Activity activity) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ECLAIR) return; - activity.onBackPressed(); - } - } - - @TargetApi(Build.VERSION_CODES.ECLAIR) - private static class OverridePendingTransitionAccessor { - private static void overridePendingTransition(final Activity activity, final int enter_anim, final int exit_anim) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ECLAIR) return; - activity.overridePendingTransition(enter_anim, exit_anim); - } - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private static class SetHomeButtonEnabledAccessor { - - private static void setHomeButtonEnabled(final Activity activity, final boolean enabled) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) return; - final ActionBar action_bar = activity.getActionBar(); - action_bar.setHomeButtonEnabled(enabled); - } - } -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/OkHttpRestClient.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/OkHttpRestClient.java deleted file mode 100644 index 69dc99409..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/OkHttpRestClient.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.mariotaku.twidere.extension.streaming.util; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Pair; - -import com.squareup.okhttp.Call; -import com.squareup.okhttp.Headers; -import com.squareup.okhttp.MediaType; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.Request; -import com.squareup.okhttp.RequestBody; -import com.squareup.okhttp.Response; -import com.squareup.okhttp.ResponseBody; - -import org.mariotaku.restfu.Utils; -import org.mariotaku.restfu.http.ContentType; -import org.mariotaku.restfu.http.RestHttpClient; -import org.mariotaku.restfu.http.RestHttpRequest; -import org.mariotaku.restfu.http.RestHttpResponse; -import org.mariotaku.restfu.http.mime.TypedData; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import okio.BufferedSink; - -/** - * Created by mariotaku on 15/5/5. - */ -public class OkHttpRestClient implements RestHttpClient { - - private final OkHttpClient client; - - public OkHttpRestClient() { - this(new OkHttpClient()); - } - - public OkHttpRestClient(OkHttpClient client) { - this.client = client; - } - - @NonNull - @Override - public RestHttpResponse execute(RestHttpRequest restHttpRequest) throws IOException { - final Request.Builder builder = new Request.Builder(); - builder.method(restHttpRequest.getMethod(), RestToOkBody.wrap(restHttpRequest.getBody())); - builder.url(restHttpRequest.getUrl()); - final List> headers = restHttpRequest.getHeaders(); - if (headers != null) { - for (Pair header : headers) { - builder.addHeader(header.first, header.second); - } - } - final Call call = client.newCall(builder.build()); - return new OkRestHttpResponse(call.execute()); - } - - private static class RestToOkBody extends RequestBody { - private final TypedData body; - - public RestToOkBody(TypedData body) { - this.body = body; - } - - @Override - public MediaType contentType() { - final ContentType contentType = body.contentType(); - if (contentType == null) return null; - return MediaType.parse(contentType.toHeader()); - } - - @Override - public void writeTo(BufferedSink sink) throws IOException { - body.writeTo(sink.outputStream()); - } - - @Nullable - public static RequestBody wrap(@Nullable TypedData body) { - if (body == null) return null; - return new RestToOkBody(body); - } - } - - private static class OkRestHttpResponse extends RestHttpResponse { - private final Response response; - private TypedData body; - - public OkRestHttpResponse(Response response) { - this.response = response; - } - - @Override - public int getStatus() { - return response.code(); - } - - @Override - public List> getHeaders() { - final Headers headers = response.headers(); - final ArrayList> headersList = new ArrayList<>(); - for (int i = 0, j = headers.size(); i < j; i++) { - headersList.add(Pair.create(headers.name(i), headers.value(i))); - } - return headersList; - } - - @Override - public String getHeader(String name) { - return response.header(name); - } - - @Override - public String[] getHeaders(String name) { - final List values = response.headers(name); - return values.toArray(new String[values.size()]); - } - - @Override - public TypedData getBody() { - if (body != null) return body; - return body = new OkToRestBody(response.body()); - } - - @Override - public void close() throws IOException { - if (body != null) { - body.close(); - body = null; - } - } - } - - private static class OkToRestBody implements TypedData { - - private final ResponseBody body; - - public OkToRestBody(ResponseBody body) { - this.body = body; - } - - @Override - public ContentType contentType() { - final MediaType mediaType = body.contentType(); - if (mediaType == null) return null; - return ContentType.parse(mediaType.toString()); - } - - @Override - public String contentEncoding() { - return null; - } - - @Override - public long length() throws IOException { - return body.contentLength(); - } - - @Override - public void writeTo(@NonNull OutputStream os) throws IOException { - Utils.copyStream(stream(), os); - } - - @NonNull - @Override - public InputStream stream() throws IOException { - return body.byteStream(); - } - - @Override - public void close() throws IOException { - body.close(); - } - } -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/TwidereHostAddressResolver.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/TwidereHostAddressResolver.java deleted file mode 100644 index 6260fbe81..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/TwidereHostAddressResolver.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.mariotaku.twidere.extension.streaming.util; - -import android.content.Context; -import android.util.Log; - -import com.squareup.okhttp.internal.Network; - -import org.mariotaku.twidere.Twidere; -import org.mariotaku.twidere.extension.streaming.BuildConfig; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.LinkedHashMap; - -public class TwidereHostAddressResolver implements Network { - - private static final String RESOLVER_LOGTAG = "Twidere.Streaming.Host"; - private static TwidereHostAddressResolver sInstance; - - private final HostCache mHostCache = new HostCache(512); - private final Context mContext; - - public TwidereHostAddressResolver(final Context context) { - mContext = context; - } - - @Override - public InetAddress[] resolveInetAddresses(final String host) throws UnknownHostException { - if (host == null) return null; - // First, I'll try to load address cached. - final InetAddress[] cached = mHostCache.get(host); - if (cached != null) { - if (BuildConfig.DEBUG) { - Log.d(RESOLVER_LOGTAG, "Got cached " + Arrays.toString(cached)); - } - return cached; - } - final InetAddress[] resolved = Twidere.resolveHost(mContext, host); - mHostCache.put(host, resolved); - return resolved; - } - - public static Network getInstance(final Context context) { - if (sInstance != null) return sInstance; - return sInstance = new TwidereHostAddressResolver(context); - } - - private static class HostCache extends LinkedHashMap { - - private static final long serialVersionUID = -9216545511009449147L; - - HostCache(final int initialCapacity) { - super(initialCapacity); - } - - @Override - public InetAddress[] put(final String key, final InetAddress[] value) { - if (value == null) return null; - return super.put(key, value); - } - } -} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/Utils.java b/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/Utils.java deleted file mode 100644 index 1e526fb68..000000000 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/util/Utils.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.mariotaku.twidere.extension.streaming.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.SSLCertificateSocketFactory; - -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.internal.Internal; - -import org.mariotaku.restfu.RestAPIFactory; -import org.mariotaku.restfu.http.Authorization; -import org.mariotaku.restfu.http.Endpoint; -import org.mariotaku.restfu.http.RestHttpClient; -import org.mariotaku.twidere.Twidere; -import org.mariotaku.twidere.TwidereConstants; -import org.mariotaku.twidere.TwidereSharedPreferences; -import org.mariotaku.twidere.api.twitter.auth.OAuthAuthorization; -import org.mariotaku.twidere.api.twitter.util.TwitterConverter; -import org.mariotaku.twidere.model.ConsumerKeyType; -import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; -import org.mariotaku.twidere.util.ParseUtils; -import org.mariotaku.twidere.util.TwitterAPIUtils; -import org.mariotaku.twidere.util.TwitterContentUtils; - -import java.io.Closeable; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.SocketAddress; -import java.util.concurrent.TimeUnit; - -import static android.text.TextUtils.isEmpty; - -public class Utils implements TwidereConstants { - - - public static void closeSilently(Closeable closeable) { - if (closeable == null) return; - try { - closeable.close(); - } catch (IOException ignore) { - - } - } - - - - public static RestHttpClient getDefaultHttpClient(final Context context) { - if (context == null) return null; - final SharedPreferences prefs = Twidere.getSharedPreferences(context); - return createHttpClient(context, prefs); - } - - public static T getInstance(final Context context, final Endpoint endpoint, final Authorization auth, Class cls) { - final RestAPIFactory factory = new RestAPIFactory(); - final String userAgent; - if (auth instanceof OAuthAuthorization) { - final String consumerKey = ((OAuthAuthorization) auth).getConsumerKey(); - final String consumerSecret = ((OAuthAuthorization) auth).getConsumerSecret(); - final ConsumerKeyType officialKeyType = TwitterContentUtils.getOfficialKeyType(context, consumerKey, consumerSecret); - if (officialKeyType != ConsumerKeyType.UNKNOWN) { - userAgent = TwitterAPIUtils.getUserAgentName(officialKeyType); - } else { - userAgent = TwitterAPIUtils.getTwidereUserAgent(context); - } - } else { - userAgent = TwitterAPIUtils.getTwidereUserAgent(context); - } - factory.setClient(getDefaultHttpClient(context)); - factory.setConverter(new TwitterConverter()); - factory.setEndpoint(endpoint); - factory.setAuthorization(auth); - factory.setRequestInfoFactory(new TwitterAPIUtils.TwidereRequestInfoFactory()); - factory.setHttpRequestFactory(new TwitterAPIUtils.TwidereHttpRequestFactory(userAgent)); - factory.setExceptionFactory(new TwitterAPIUtils.TwidereExceptionFactory()); - return factory.build(cls); - } - - public static RestHttpClient createHttpClient(final Context context, final SharedPreferences prefs) { - final int connectionTimeout = prefs.getInt(KEY_CONNECTION_TIMEOUT, 10); - final boolean ignoreSslError = prefs.getBoolean(KEY_IGNORE_SSL_ERROR, false); - final boolean enableProxy = prefs.getBoolean(KEY_ENABLE_PROXY, false); - - final OkHttpClient client = new OkHttpClient(); - client.setConnectTimeout(connectionTimeout, TimeUnit.SECONDS); - if (ignoreSslError) { - client.setSslSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null)); - } else { - client.setSslSocketFactory(SSLCertificateSocketFactory.getDefault(0, null)); - } - if (enableProxy) { - client.setProxy(getProxy(prefs)); - } - Internal.instance.setNetwork(client, TwidereHostAddressResolver.getInstance(context)); - return new OkHttpRestClient(client); - } - - - public static Proxy getProxy(final SharedPreferences prefs) { - final String proxyHost = prefs.getString(KEY_PROXY_HOST, null); - final int proxyPort = ParseUtils.parseInt(prefs.getString(KEY_PROXY_PORT, "-1")); - if (!isEmpty(proxyHost) && proxyPort >= 0 && proxyPort < 65535) { - final SocketAddress addr = InetSocketAddress.createUnresolved(proxyHost, proxyPort); - return new Proxy(Proxy.Type.HTTP, addr); - } - return Proxy.NO_PROXY; - } - - - - public static long[] getActivatedAccountIds(final Context context) { - long[] accounts = new long[0]; - if (context == null) return accounts; - final String[] cols = new String[]{Accounts.ACCOUNT_ID}; - final Cursor cur = context.getContentResolver().query(Accounts.CONTENT_URI, cols, Accounts.IS_ACTIVATED + "=1", - null, Accounts.ACCOUNT_ID); - if (cur != null) { - final int idx = cur.getColumnIndexOrThrow(Accounts.ACCOUNT_ID); - cur.moveToFirst(); - accounts = new long[cur.getCount()]; - int i = 0; - while (!cur.isAfterLast()) { - accounts[i] = cur.getLong(idx); - i++; - cur.moveToNext(); - } - cur.close(); - } - return accounts; - } - - public static String getNonEmptyString(final TwidereSharedPreferences pref, final String key, final String def) { - if (pref == null) return def; - final String val = pref.getString(key, def); - return isEmpty(val) ? def : val; - } - - 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); - } - -} diff --git a/twidere.extension.streaming/src/main/res/drawable-hdpi-v11/ic_stat_login.png b/twidere.extension.streaming/src/main/res/drawable-hdpi-v11/ic_stat_login.png deleted file mode 100644 index cc6a7ed2b309b73ab74a34221a51770b4bdbe073..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 764 zcmV;y{om0BH;Nz+SfWNKVLK?Y6zZ0C1cAkrxP z>w$V#g~$cEij%{}kzkJC_)6{=U={auWO^XjZR~b81Y~B@Ynphxsf&TfG|g{W$HlYG@nR_mCM8fkv^NAED<3`b5t>$AK2TJ4imu_C&(S z&3AxiH3IYj<3*_sO7zD7a$hj$-malOv^NJW;uT&1v>{&ouci%jhWpd04odVd0dy?Y zpAEDU;{hbJ=*7g)qPh;CS24=Aj=NIdptC2{NrClrCQMWwIo#JCLS7m!^@*^xs9JdSjg z3|DmeV$Rg7O`+Ro>aRRgkf(@FmMUWHg?b5Ji%MS*C{!eQKc@xlgMwNS7^%|qH4R7* z2I_HOq)OA*R3HPTrK58Cnhs=*RHgJy36KS~*VL1?qw}66p>FYEi#t>h(_^K@?j0000mS;Zz diff --git a/twidere.extension.streaming/src/main/res/drawable-hdpi-v11/ic_stat_twidere.png b/twidere.extension.streaming/src/main/res/drawable-hdpi-v11/ic_stat_twidere.png deleted file mode 100644 index 5662508de0471280a5efbdee09e535662aaf573e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 885 zcmV-*1B(2KP)KE7VXl#g{k-33(qFX@y?MWok`jo6PpeFM2UbHnt>RW(G zM(rN$yU-P&I(rMM?6L=H3F$uXU}vuGPY zZ}Ncf=f{skrp26aH4SE>ap*jLuBR489N75+nunamWRz~xwjH$v=aab(56-7^of-h_ zYm~=_-zUVL{f7@%e=EJ_I*#ecM1e^xeN6p z_z|=kd&kSi1&Zfj9#9J%Rv|gESgvPy;Yl|1Qe|veViC zWAeE|BGaj>Br>Penq|e$@~fX#WUXsWR{K1lQ*>H`jK-A2r+(tuM337m9&DeBqDmkC z-AF%1`%yD6E{blJ2h_;hZX-q}`R)hWqUnn}b@e?*^O5x>ZZCN_jE(>!c!}k$GFL#f zg(N$hQ!e##Ce$6Y2+cx9#!_LSJqV0oWi1QH1m2A5QwAH_e@PK63RRhDn3Q-@M)WF98xHc zDkiauBhzw$>1lE|a&N2Fp3uR3JPnk9sa6qCfHE3OP*b>83*`~`B&r9>{3>e| z0|h7(eE~XvmZM7hyUqMYLLEbmKzUzcl{)O|$n*(i;oFGZRCR1_xB)A-5G898Mx%m+%xC9=fD4)u*{e*cFg&i z2|!ZeiA2Lol*wc)YPI@4%d+P?oz8KUN>y&R+uvKQ)|+az`qbm`R3x+V0(xhV&1Pqi z?0K`Oqmfddu zAP3R~K$fjarLu?}w~^!#9_>Sx1^k8fbUB9z2vG-e;*k^^`FY3@)UG`70k?pNGP$z*aF;AcWf5L+~x%`;Z3b+D#X zK9b~7!6`}teK(v==NgwVl}c^a>-BqscB$2B&$(Q#Z(>!jkl`=1KXzC_8<0)hf5!bK zB)<*#z^@%L&Ev55L;=xg^cMomToBojY)NNAb``tydi@+K{vry9#bR67@uJjW39Q#) ziYcGZcOWIv8Z7sC1i(AL-+x2uJvNa@7#fYnR|KAx3g)jv%DqylbTtqNR7ESG#c()$ z0p)IEYLp8>TVe3Q?cxKyE+$jYA(2RA0m)xtOv{Ck835TSm&-Q?LHaBh3X?7TFk#H|H$V`$X}3@)ED6aa=xEL~+Ap|LkG*~n=Bxy)(c#95-;@~K# zgNW!LIw*8o3T`JMPVkC*b2{&=;}$z1sI&b{~ixaWJ%xjdzBpNF!~{`-0X zY#HuR)T79j0b2z{)3nR2R_hX)4y!h6KNUrJ83+WP27|$dt*31ilvFA;;&eI_>|X&+ z(Zlh&$S#*_75Nt52cb}?wwEAAA1o{^sHIXVju-)TGaIk$`FuXz;cz6EmzOi~c)a|t zK{gr-Fkxw|g=i4!^PsfW4B>=lkpR`cV$H*3rr7boy+w*?f)@ z6&M*X8qlOc;~l<-plg`5A?Bm#4zMQkQNH~+Ka4yg_Q+0<>j*G6H+Qa9tG!3z7Z?N{ z@WbQre8;g1`4~n+pw9|9Mc10#*TZVHdb1-yHk&=e;s-WGVMVgwWGyg=g9dQhQN(@| zyd%47Q&Urm-5H!FgO4bGkpP@n`Mc>89vNrBZn#T!Vuqx2y7%3pO2=$?O~RG3Ihl z?Xkkz3}vlFA`v-=F**VylgUxmUgO}D#ZWipjnc(Y6^=ji75(F24cznl{daM09B9h` zP&CLLJjVEfMdyzx8yU3+HD2Q&FTe!&N-(+9C9BS+3}hjZNSwrY9;5T7ay#8koKv|) z4)dhZXlOY9BA03#Kon+YXU8y1Ax>Io+_G{AQUde3uFvoq6n7OslrovjaJgK*&8e<3 z-Ld|8Mydq4UnmrA5Tvl}9dt)WS>+v)x9K8SCs+yU#3oEey&o|X>Z#QCl%>Q>zA+%|)~I&Rzb0@yOxqv$`N=r3|= VFWXV)1=9ck002ovPDHLkV1itec_jb< diff --git a/twidere.extension.streaming/src/main/res/drawable-hdpi/ic_launcher.png b/twidere.extension.streaming/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 4ce12c012355dfbac9269a72ce2e00f8efacf4fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3726 zcmV;94sr2`P)=Q+2!tLlbdJ@0#O)j8eYeW%^Dn|9M~yL2loER2bd zkH?29E-vm*<)@M++F@h-C^%B7G&Ugg45R4mQYny z#V!OZHxoOqe$GbM@aJt+-&T5GJsb67JN@VPTU%S>w*_ZpWF)zxqXSI0Z{G&LznR!M zs^@ifcK+oY_T5I`t6#gFW1H2b`rZ5LRc}M}^U%;x@|J+`jc-~&T0mMrT0mMrT0mMr zT0mMrT0mMrT0mMrn{R*o@rM@BX4}ky0$pQSUoW6fb$3@^ETd~Y5oLX5=$rTo0j(}g zV?kbkIcXpkTUzku^=plE`t92{7=PG+ssTro_nQ$Q0Vbz!e;t6{zI}`3=@HEJMPs?m z87u9iHVIaOE?_<)0!xE~J95LTVUx1c$0f8_NN2{0N4{n#ehQLIPvPg%yKS+G~V?$-LbGhz(+-rv}ZrZm5aX zMbUL#6yDHB@l6AiL>ZwpT7a@xQ<5yN#aVN+|lgefhnJh zfhdilq>UrvXLL03Gd7=^!FN1WD|ygybTDj3CJfl9b%k;&~QR z;7~JddEqcb?n|)CuHd!1ZdqwB{2dN1qxAYV?#QFB3nBYp0P)P9m(DvB?L?6 zC`Plh3wp>wqi4@z+{+8)WfmytFhUUn)WsmE%8(OtOi`Bs=``)@Q-TiG(Aw%Po<4p0 z7uXt^=2_*F@^*5R2a0YQA}`z+Io3ktSXd&@(h_CXHmE&ghZd0ty-rRTrtlhZb%Wg9 z17jYZ7^e`sebouMEe6PIHy}ucDCjgqVW$Bn2BeSyVd~VUeO`JPm?+p5fR`^{VrF(4 zql$jCcFIs*lZw>5D+rHwfp>@j&IK7@NZ$2n7m5tjo#8eVo)@E@;ItE%esawqff**p z3{zN*l56A=3C0MJ!rh(Z0R=(IEigt_lRk1<^^w;`YS%~p?bFEb&?jId0#iUh3OY}% z=_K+=_hFzhQUbUx>{(kCkW3pYKtlp|}OvcK+zKwZ{;J)G&qA2+d@2a*v!KjZw}~kc$)& zf<%d077~H*x=5tf86vYu581c$2$UXj+j;3Cqfr-0GF`-$>EcGdF2d4JA}HY`LSh|o zi5%;7^#tiS&RzW-p20`qapf@FgAT&=@_tAH_QHk1@gq3CzrgX*f8juYB>wx++Ew-W zpT(x`K0uf_3GvSHxMlB-5qk%W5Tr43(HJG@F@mI^>0UvglQ5XE<(`4-lYz za3Mg>e!r1>{s+g4KXY(G;~X$M_vp(!tg=vx@y{&qstL=NB^@C!ht|W&fA2b+OG-Gt5yqIDlJAb!9pgh2h;+(Cj3gg%ZUu<*C`25ADiw!d zn7PTp5#y1zm})ggM#XhFX4b+XsT?+8v2gIUgJ+Nq!8*o;4+FwM2~k2(b&O}wk@b)Y zJg}Z~{P(p|4ss(vYoKaw(gSO)AptVM-CIJqv(8J~}0m2GXV9x+$)WI&T8n($* zu!%2)<@Ia`0&c*NR@^q8x{&x$2>I>fbKiFk8;7n#6&QPe? zu0gU+D1&8mK1{DB!oVvS`eG5RJdP8TJ!?>YeFsK#;b#Qhu)(A0dtc8>`<%!!L^@>R zrZ|@zl!4nRh8V~_j=@|Vf^>qUgQ21m=&7}aEjh?GgQ=DP)xbJc2CKwMSjCsYJf;Yy z*D_$}cLOKgd~wR&8kTN{-hmPM{D$1pXuNv$N}~_2pBzv}Lm$HJQgK6+jhgG$=+8ca zzO19&$vsQ*Kw#HnOgvfQ)?vFI5W9;^3k!<~woO3ZB@gtZ9YSx~Vf3UN zMt8~)bSEp-l|*IQ5kzE$!jb@4k&CR->tLBy3rm7zL6C$A6%fXk!!))Orcs43ipa$2 zD+$mgN1gBvgN|1S^g~i%mLx+?OF!qNT?vRmVRw*;y@6!PyB2}Yq3Bv?^JFrt0K=wgCbfb_a{JbSjfyOOjz7`6^#Vs~<3ei{Q!moX|m0!1~c=IEM! z#~4XbdyLa?^(k^sEzAj$c?MHGglTmU5+q?t4a`!iVY((0ataf-pIQsE%ISPXnwyt1Td>l?uQ{5+PHmbiA*A@Q#MSV%ht#Jh)ehJjIqqY8!%U}0f_8_bg@ zPaq%aL`S(D$MyM=>VbPdY$u zIza0nO27oih~Oxt+&7NQp=Ym9?iV`E&CM7b9K_`0BpyG0jJdfvt_{{6bFC^QKGZ&D z`ri>CzER#itW!+tVWsLGHV`%-2B@#E50#abxE>LT)N6VeD&LDS={{V^jf7F=EhQK# z4QQ6KIv;?5fB@v=T=EbmLsZppK4? z;?A8r9As7xtB-+K%|)7W(MJPP4KH;-TR~!Xn}@^($p*{9jr|0vxVRX3>6hT0QjEgl z67DBT{r&x%TgJ!7F)=a0UBhw@a}LWt3=Z!e)*fq{^FIi3hb2 zBpwtCIW|}}Xf}8Tg1L)_asU2(?id5g&SN=@fnnFPy50we53w(jgH&fQ)hS+m{i6zs zcNCwr`LN^j6Az9T4}ysu=R=8I&!F%#7Y~Mqqp9_fMgVQJ4&ueb+RRxD7%$#s8;Kob zV(0NdRH3N5Mm?;)*g8lx+*F^x)Lo?tOg$7oR6KCLF4g+g6Y@^rYzq)S;H|_1Q3b>6 zeQw%F>dyEOP<&YN+HU_h)0TkvPV7YLgI5i)&BTYD`o5}E>r#iNDQyXek9|#Rvt09` z`c(bnwIv|+S>;>PmVns$<6G92fbQPCi_aytFx*O?vp-B*0%FfS-?Fv@G%zrLZ&_Oc z>hA8wx2)~_zsV1zf0Fi)_H9G^Ne4-Xc9{;Y^=&(2*t0g~AGQPNd(z)XKa&2w4gEy= s$1c@R+Z@A>Yh(Ui`?p%!O|#qo0j%qhkaN&CmjD0&07*qoM6N<$f+h^t8UO$Q diff --git a/twidere.extension.streaming/src/main/res/drawable-hdpi/ic_stat_login.png b/twidere.extension.streaming/src/main/res/drawable-hdpi/ic_stat_login.png deleted file mode 100644 index 7ad61d275eb059d096748db74a8c3bb97a77e7e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1301 zcmV+w1?u{VP)J_sw)QNJDWzC+bTpqVsIa!S1|uUQ(9qCOE8F|~JKWvf zfj}StB1qlT)YMNZSZZpjKu1T%%FxhItw6HQ@9*#7`T1EmI5=oc15Gwcd^aQ=Vy=(@hQkkBfE+YAs za~>8J1}P~iOnMdB=H@1JbacS^`MFAPq^_Z_ua6FvmX^jSCTW?OnGh2b!zmcnOJidr zY;SLKS}(Z>6&n~Bpo5VblLCu~h=APOT;_Rvqvhpg(9+TZe}8`_l{CA$x`N8eO1QbX zQ3?*hNR83Kl9Q8JFk@q5XlQ5v{QL0m0M*siaBy(I1S4$)Dk>^KQ&W=~d}3k(y1KfQ z1{)q8rh_FVC9zUTCip~KaW|No}Q+Ig@=cW z#BBg~9RcO+SaxA)X(^*HS9^JRfti^ZIvA-P7A!b87;0;4x%!n_hhr))FHflvgf93$emX?<2U;zOEA{;rAhP{l>=L4S6l(o~-Qz$7Zfy2YYPal1KeZ`SS z2P0{d14ED4&k73*At50F^!4@Sg6!<K3` z?9s%;1cHKsz}eXu@Dy@=ea$po{Mg&uLwkEW*x1;}0btGHi+u!#VC(DabTCg(Pm!X* z{An)80t9YtZ3R0!JGte!5efi$;pX1&&k@+(Gg^2WdZJJG`x@yU^*DtQC|**Ctz|iW`bjV zxw^Wtj96=Ugc5_1-Af0vvakPc>PX{lB)ay^5n zs3<8gv4WV&i;D|780qlLti)!g4nuVij%0>$kBZ^Q!!d}nlH9Nqf(gh>v{Lobs_M(& z942WL5-|Et1SJ1_Gc&Uays(mW%v-3_FgvK8o0}V4US8IdOV3~8cv80s{23}XHkNN; zVUa=FhWyY|10|`gGXm91?xH^x{tTstxGK9;eE(9}<<~s;ZNdHpZe$rnjYyA?00000 LNkvXXu0mjfKNMx} diff --git a/twidere.extension.streaming/src/main/res/drawable-hdpi/ic_stat_twidere.png b/twidere.extension.streaming/src/main/res/drawable-hdpi/ic_stat_twidere.png deleted file mode 100644 index 62008a2333dc0a163d9eaff32ad5974eb7bd064c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1277 zcmVY1mdTQHyS-;Qz{-(XR4*jC0^NVuP?*ZoL=Vz#+qx0A8 z?d=~-N#{>ebJy6|xKX826)r6;-Ag_-6pM|GEny43IXF0wxw$#%>gs+d+w=1?U0z<& z(a{kxLH-^d9?lbjrKhJK85$beo0*w?DA3Ezudc4>{{H^Bqocz?2$r3ltuit)`f#OQ zfZ46V|h)jt*v6PjEoGf*jE@7Yj1BCgRva@QZSZd zVz9KdG#M;BJeP{z0#^pm6a8$sHosg z@@EWS0|NtMu=x1+|A0wwMMXvA?(R+o1_rW!gtoW07yXBBZf-a<+Kr{9C7&EPwz9I4 zkJZmZ`N_#i8W|bk`vGidXh;ke6B8o@)6>(V%F0Tzv$NyQq?U4gd`vSlGXy|;dwULq z@M9g+RWdZx#l=OctE;2U%}p6>baYe<78MnxQddNMZpuGq!J1y@bVIRM~T+qnuT zz|_~*)BOBAvDwVsps2>i#>8Nek&%jE-@kt+Z*OnD3EG5>jSWB6*VpG^0GQHEso&t< z-X1kHH1KuJL4?{k4?x+b;H`Ot}be9Y~(lh z(f~F)J1YhY3JOvoG$PB(%Om!@#w$!RJWHwnjq_+50QB(ikn;}eu>7Ig+FIJ*-xu!x z`1nW*3kzZ}rida~ad9!RKBuv%2n-7_vH;-YFMEx@|vMS+1wR_u|A~;CT)tAQBY7ofq{XqI+8A)oSaZ;X({#h_j6U0 z3}9^Liosl6UEc)5#-5&@R9IL@!NI{=!JVF-Qh9kfZxc$&0gN?XF_?>si&kKuVQVQT zCx^Veym*U1<>3d%PzFCZLubc%H08FoHpO9&wcFdWYowzgji#wu70W^HZF zXXR^U{Z>f+&vo=d%t|)O6v2+z0JeY6w;ydlG4xp&j~STw6G22oLeRpSAJY8f0H%v1af n^%)@A`uIJ*C~A8*pRw*A{Lx88)#l`V00000NkvXXu0mjfk-%K1 diff --git a/twidere.extension.streaming/src/main/res/drawable-ldpi-v11/ic_stat_login.png b/twidere.extension.streaming/src/main/res/drawable-ldpi-v11/ic_stat_login.png deleted file mode 100644 index 55f4c57c0752d1985f5318c52da28dda0096ee51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmV;D0d4+?P)coytlGHWo2Pu}EhlT3LvQ*jQ?1ieM?&3N{M^{os`HZxIUE@!?Ft@Y&2wFsTXP+})KsjpzscZ(= zd%X4o)T$ENK{mKR6IRR>m wdX7b1tNjV2)yeHXD5(A)P#Q=T$uINS03cp%x=)Qj3;+NC07*qoM6N<$f^4CyjsO4v diff --git a/twidere.extension.streaming/src/main/res/drawable-ldpi-v11/ic_stat_twidere.png b/twidere.extension.streaming/src/main/res/drawable-ldpi-v11/ic_stat_twidere.png deleted file mode 100644 index 2c6c59919faa319b9fd444219a31be7ff6ccd3c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418 zcmV;T0bTxyP)Y5Qei+6F(6lh+^lTuodhAwxWeaLcm5#tt6nGja5KNrA;8D5iJA@|AbiD*~H2Z z{KR-ZZ*|AmIS+p#fFr+{a(CZfAth zAg%%hc!mtTz#1GNCh@NJbu`3An7IQ*$l9tVeh#6_s0wqnZV1L<6k6YE#DqnH`!Eb? zIET6|7{gCO&b-prLca!&ZrjD({Ht5?o zWwr^s;br~tts$mt@|Kb6qr$&|?v1=Ud;P0WOcq^3$-e&o?jAS)6UcjJx%Fp)1^@s6 M07*qoM6N<$g2IHk!2kdN diff --git a/twidere.extension.streaming/src/main/res/drawable-ldpi-v9/ic_stat_login.png b/twidere.extension.streaming/src/main/res/drawable-ldpi-v9/ic_stat_login.png deleted file mode 100644 index 3545323dd4d515d696b6e90f863d9d5f657b8e33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmV;30eAk1P)U*HL2T;=~kXoEE-QM1A3UulYpkk1w zxBveA^C~JTI)yiB05vH9HH85U?&Rj?2HE6AFfFyVwn_s1kp$G(0<`HhK@A{xx3sj# m0yUihGP#J-fD)`U&kq1hp?w~rEoD^z0000Wp}$4+HfxHg>pBD1Ado}E3F9U1wxl5p!yY<|+;f1a5eS|k=(e#QFm2oOybEavf?&Zk z%^~O-@Cq2f3-H+1`o8a<2(2`r8;PQ5A7>yE03CTr$P?nEWmz7e>Ey#8NS^0fQ51)u zdw|+TQ7EPN*lEXcobxY+Hd+T?sEdlHLMrIVtOD1~{{*-Qh8d!Q&N zpbvp@n?OH<9dK#h=7KiE1orOAwi)>zU<&#XxU>oMN*$tbYTj0XHCIS1nQ6^Dv=IDI zlWYR5_=n)e1k0w?sZxF9)0(^_3LE%Ut8I7OCJ<(D5Ok8>Fb_Um z;OD+M)*UF&05pJGP`#CE;kQj3i!e>_1IxJmYsy_vzMG*9bgq?-WJh#`G2QZ`FAHd* zxz$}fwnMsYvGJ*(`d)<**$YgOcY^sob>h?aNjrE19a*8zhilhk}^=wBc(O>aWUlNm=YJ9_{C002ovPDHLkV1kKD B`#Asr diff --git a/twidere.extension.streaming/src/main/res/drawable-mdpi-v9/ic_stat_login.png b/twidere.extension.streaming/src/main/res/drawable-mdpi-v9/ic_stat_login.png deleted file mode 100644 index bf03f9a813901d150c44667c22e612a730addbd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 529 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 diff --git a/twidere.extension.streaming/src/main/res/drawable-mdpi/ic_stat_twidere.png b/twidere.extension.streaming/src/main/res/drawable-mdpi/ic_stat_twidere.png deleted file mode 100644 index 05e41a6cfc85916ff568cd7f1ac32b6c3aeb8585..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 848 zcmV-W1F!svP)P000>X1^@s6#OZ}&0009QNkl0gS9ilAQK%(=h6$JyB#)azfb*ZWn1 zbar+sSy@>~NlAG#Ahz)7=?OPCH<+HD7D;HCbaZqG$VZ8gnVA_G($?0dWM*ch*=H_IG-EJ3qAb!7JhL}ty3DVr$jDdjxTwPruH8oX$m??ihCuZRD`QUcDg|i4*US5_V z>duw;`A~-w!^6Y4yu1|Iu;~P`)+|fB_#e$NIyx$5gkm4n%w z;S5e=aEA<}PPCTQ_V%{u*Y57F#wKKaeO-ps*Viiy7?aUxgv;d;CZK3#W<;?Zkw^pv zgF$5KbUL9PAyRe^4-eSb*pMN$wY3t2!3PHip}I~iW(G0$@t&Ejt*yc1@v!zuGepSd z=B5m(uC7)Rn@ZR8_V%Kyt4oxPJ&6}hF+M(ysi`T^gLu(tTU%Q)q^hba3BpALI~)%5 z_xB4>qL|Ux*q9jBM2Ole8B$(e{w#zG89a8>us00M@^QD!;Ns!}(P%UYvcJDCL(0m^ zl#e)pVHBYv;w_9s!YTSGUzb5E&&+^q94u>7Hv$I|a^4`GzTmLDa aME?LluWl(rK$vs@0000JJ$b$zDQYao=Vj}k< zxr7G~W=NV)YUG9E^PBdZmVMUVYpuQ4I?k!t^=r=F`}g~<-)HT;*8Z(EQA3>{QJv@C z-~>=AmF57v30sEA?=AY~ilW!m>KH2k5?@b32eB2Fi9Nxu8<5ME{<+;U z0Z4o*%BQd`Ia|0%+)h9~<%~Cmr2>%rLU|pq8Ag?ChkkCi1988gjy7Bi5GUV5#6(Yx z4xqCEhQ zxr2Wj5GBXBRQG=X;@Re!CixZ`?NhJgJDKwb*j&eCwxf04F~%A|dT3?Bdk+ns)+qq7 zk?U6+lX;2We8(6wK>U$r(OmzDjc`mzo~V2)3LoWH2!IaMPHGez)8=tv zM&bVp8|j$IQ8W)Z#%SGDfD3qR)p+fov2!U;ppEOdb0l&L&9yn=Dne9%=iFVO5tSNe z2@QT%@6r2XIlqf7&XGtjdQCavG67_kX-pA)%k_Pjlm;@5N=l$3JZ{Xk)R3uC=J{O?;JF}-0BQoj zv~aF&Ey}uBG^Es)vRn3kWH0HV%<~+b{5}>E!U@13k+N%Oh~NN15)z^+03ji&1`rCO zssJG%st%w)98e|&$zwvsB#}DB{uh8`qVW!gY>;IgT8MfA5V#76dIP9{s1<-QWTyTb zO7fbN@ji9(r5{|s*93rOOvr%#kpb`pfa${kd1@n@7-ps6Ct%Z2L46DbU~P|qp`HOk szSes+J=M=39$Z}2ZU6uP07*qoM6N<$g4BPa#sB~S diff --git a/twidere.extension.streaming/src/main/res/drawable-xhdpi-v11/ic_stat_twidere.png b/twidere.extension.streaming/src/main/res/drawable-xhdpi-v11/ic_stat_twidere.png deleted file mode 100644 index 3439e626948c58c7b6c73b53e29b1abddf3881dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1324 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 diff --git a/twidere.extension.streaming/src/main/res/drawable-xhdpi-v9/ic_stat_twidere.png b/twidere.extension.streaming/src/main/res/drawable-xhdpi-v9/ic_stat_twidere.png deleted file mode 100644 index 2b49bf7745d061f5deadc4c6f3a4cc89d94f68fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1053 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 diff --git a/twidere.extension.streaming/src/main/res/drawable-xhdpi/ic_stat_login.png b/twidere.extension.streaming/src/main/res/drawable-xhdpi/ic_stat_login.png deleted file mode 100644 index d4994d08193ebbec464b1cd3ef668b7cc21c8a2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1829 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 O0000 diff --git a/twidere.extension.streaming/src/main/res/drawable-xxhdpi/ic_launcher.png b/twidere.extension.streaming/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 40dc3ffca94c001c53ce57c19281411cb735f44d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10713 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 - - - true - - diff --git a/twidere.extension.streaming/src/main/res/values/bools.xml b/twidere.extension.streaming/src/main/res/values/bools.xml deleted file mode 100644 index 9c358e248..000000000 --- a/twidere.extension.streaming/src/main/res/values/bools.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - false - - diff --git a/twidere.extension.streaming/src/main/res/values/strings.xml b/twidere.extension.streaming/src/main/res/values/strings.xml deleted file mode 100644 index 074348612..000000000 --- a/twidere.extension.streaming/src/main/res/values/strings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - Twidere Streaming Extension - Select accounts - Enable streaming - Streaming service is running - Permission request to access Twidere - - diff --git a/twidere.extension.streaming/src/main/res/xml/settings.xml b/twidere.extension.streaming/src/main/res/xml/settings.xml deleted file mode 100644 index 347f02bf8..000000000 --- a/twidere.extension.streaming/src/main/res/xml/settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/twidere/build.gradle b/twidere/build.gradle index bd5154248..3ca0b2d3f 100644 --- a/twidere/build.gradle +++ b/twidere/build.gradle @@ -22,16 +22,6 @@ android { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } - packagingOptions { - exclude 'META-INF/DEPENDENCIES' - exclude 'META-INF/LICENSE' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/license.txt' - exclude 'META-INF/NOTICE' - exclude 'META-INF/NOTICE.txt' - exclude 'META-INF/notice.txt' - exclude 'META-INF/ASL2.0' - } productFlavors { google { } @@ -95,11 +85,14 @@ dependencies { compile 'com.bluelinelabs:logansquare:1.1.0' compile 'ch.acra:acra:4.6.2' compile 'org.jraf:android-switch-backport:2.0.1' + compile 'com.fasterxml.jackson.core:jackson-databind:2.4.4' googleCompile 'com.google.android.gms:play-services-maps:7.3.0' googleCompile 'com.google.maps.android:android-maps-utils:0.3.4' fdroidCompile 'org.osmdroid:osmdroid-android:4.3' fdroidCompile 'org.slf4j:slf4j-simple:1.7.12' debugCompile 'im.dino:dbinspector:3.1.0@aar' + debugCompile 'com.facebook.stetho:stetho:1.1.1' + debugCompile 'com.facebook.stetho:stetho-okhttp:1.1.1' compile project(':twidere.component.common') compile project(':twidere.component.nyan') compile fileTree(dir: 'libs/main', include: ['*.jar']) diff --git a/twidere/src/debug/java/org/mariotaku/twidere/util/DebugModeUtils.java b/twidere/src/debug/java/org/mariotaku/twidere/util/DebugModeUtils.java new file mode 100644 index 000000000..6be3a40f8 --- /dev/null +++ b/twidere/src/debug/java/org/mariotaku/twidere/util/DebugModeUtils.java @@ -0,0 +1,43 @@ +/* + * 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.mariotaku.twidere.util; + +import android.app.Application; + +import com.facebook.stetho.Stetho; +import com.facebook.stetho.okhttp.StethoInterceptor; +import com.squareup.okhttp.OkHttpClient; + +/** + * Created by mariotaku on 15/5/27. + */ +public class DebugModeUtils { + + public static void initForHttpClient(final OkHttpClient client) { + client.networkInterceptors().add(new StethoInterceptor()); + } + + public static void initForApplication(final Application application) { + Stetho.initialize(Stetho.newInitializerBuilder(application) + .enableDumpapp(Stetho.defaultDumperPluginsProvider(application)) + .enableWebKitInspector(Stetho.defaultInspectorModulesProvider(application)) + .build()); + } +} diff --git a/twidere/src/main/AndroidManifest.xml b/twidere/src/main/AndroidManifest.xml index 1194b46f0..a1428b065 100644 --- a/twidere/src/main/AndroidManifest.xml +++ b/twidere/src/main/AndroidManifest.xml @@ -1,65 +1,65 @@ - + + android:required="false"/> + android:required="false"/> + android:required="false"/> + android:required="false"/> + android:required="false"/> + android:required="false"/> + android:required="true"/> - - - - - - - - - - - + + + + + + + + + + + + android:label="@string/app_name"/> + android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP"/> + android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP"/> + android:permissionGroup="org.mariotaku.twidere.permission.PERMISSION_GROUP"/> + android:required="false"/> + android:value="AEdPqrEAAAAIKbKATV1AGbLB4kem3w8QaPVJSPVVumbMHxkfwA"/> + android:value="true"/> + android:value="480dp"/> + android:value="640dp"/> + android:value="240dp"/> + android:value="320dp"/> + android:value="true"/> - + - - - + + + - + - - - + + + - + - + - + - + + android:resource="@xml/searchable"/> + android:value=".activity.support.HomeActivity"/> - - - - - - - + + + + + + + - + - - + + - + - - + + + android:value=".activity.support.HomeActivity"/> - + - + - + - + - + - + - - + + - + + android:value=".activity.support.HomeActivity"/> + android:windowSoftInputMode="adjustResize"/> - + - + - + - + - - - + + + + android:theme="@style/Theme.Twidere.Light.NoDisplay"/> + android:value=".activity.support.HomeActivity"/> - + - - + + - + - + - - + + - - - + + + - - + + - + - - - + + + - + - - + + - + - + - + - + - + - + - + - - + + - + + android:theme="@style/Theme.Twidere.Wizard"/> + android:theme="@android:style/Theme.NoDisplay"/> + android:theme="@android:style/Theme.NoDisplay"/> - + - + + android:scheme="http"/> + android:scheme="https"/> + android:scheme="http"/> + android:scheme="https"/> + android:scheme="http"/> + android:scheme="https"/> - - + + - - + + - + - + + android:resource="@drawable/ic_assist_twidere"/> + android:theme="@style/Theme.Twidere.Dark.Dialog"/> - + - + + android:windowSoftInputMode="stateAlwaysHidden"/> + android:theme="@android:style/Theme.NoDisplay"/> + android:label="@string/label_refresh_service"/> + + android:label="@string/label_background_operation_service"/> - + + android:resource="@xml/nyan_wallpaper"/> - + @@ -522,53 +525,53 @@ android:exported="true" android:grantUriPermissions="true" android:label="@string/label_data_provider" - tools:ignore="ExportedContentProvider" /> + tools:ignore="ExportedContentProvider"/> + tools:ignore="ExportedContentProvider"/> + tools:ignore="ExportedContentProvider"/> - + - + - + + android:scheme="android_secret_code"/> - + - - - - + + + + diff --git a/twidere/src/main/java/edu/ucdavis/earlybird/CSVFileFilter.java b/twidere/src/main/java/edu/ucdavis/earlybird/CSVFileFilter.java deleted file mode 100644 index a7800c1f4..000000000 --- a/twidere/src/main/java/edu/ucdavis/earlybird/CSVFileFilter.java +++ /dev/null @@ -1,19 +0,0 @@ -package edu.ucdavis.earlybird; - -import java.io.File; -import java.io.FileFilter; - -public final class CSVFileFilter implements FileFilter { - - @Override - public boolean accept(final File file) { - return file.isFile() && "csv".equalsIgnoreCase(getExtension(file)); - } - - static String getExtension(final File file) { - final String name = file.getName(); - final int pos = name.lastIndexOf('.'); - if (pos == -1) return null; - return name.substring(pos + 1); - } -} diff --git a/twidere/src/main/java/edu/ucdavis/earlybird/ProfilingUtil.java b/twidere/src/main/java/edu/ucdavis/earlybird/ProfilingUtil.java deleted file mode 100644 index 525cd6e98..000000000 --- a/twidere/src/main/java/edu/ucdavis/earlybird/ProfilingUtil.java +++ /dev/null @@ -1,70 +0,0 @@ -package edu.ucdavis.earlybird; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.os.BatteryManager; -import android.util.Log; - -import org.mariotaku.twidere.BuildConfig; -import org.mariotaku.twidere.Constants; - -import java.io.BufferedWriter; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; - -public class ProfilingUtil { - - public static final String FILE_NAME_PROFILE = "Profile"; - public static final String FILE_NAME_LOCATION = "Location"; - public static final String FILE_NAME_APP = "App"; - public static final String FILE_NAME_WIFI = "Wifi"; - - public static boolean isCharging(final Context context) { - if (context == null) return false; - final Intent intent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - if (intent == null) return false; - final int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); - return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB; - } - - public static boolean log(final Context context, final String msg) { - if (BuildConfig.DEBUG) { - final StackTraceElement ste = new Throwable().fillInStackTrace().getStackTrace()[1]; - final String fullname = ste.getClassName(); - final String name = fullname.substring(fullname.lastIndexOf('.')); - final String tag = name + "." + ste.getMethodName(); - Log.d(tag, msg); - return true; - } else - return false; - } - - public static void profile(final Context context, final long accountID, final String text) { - profile(context, accountID + "_" + FILE_NAME_PROFILE, text); - } - - public static void profile(final Context context, final String name, final String text) { - if (context == null) return; - final SharedPreferences prefs = context.getSharedPreferences(Constants.SHARED_PREFERENCES_NAME, - Context.MODE_PRIVATE); - if (!prefs.getBoolean(Constants.KEY_USAGE_STATISTICS, false)) return; - final String filename = name + ".csv"; - new Thread() { - @Override - public void run() { - try { - final FileOutputStream fos = context.openFileOutput(filename, Context.MODE_APPEND); - if (fos == null) return; - final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos)); - bw.write("[" + System.currentTimeMillis() + "], " + text + "\n"); - bw.flush(); - fos.close(); - } catch (final Exception e) { - e.printStackTrace(); - } - } - }.start(); - } -} diff --git a/twidere/src/main/java/edu/ucdavis/earlybird/UCDService.java b/twidere/src/main/java/edu/ucdavis/earlybird/UCDService.java deleted file mode 100644 index c9a0b6df8..000000000 --- a/twidere/src/main/java/edu/ucdavis/earlybird/UCDService.java +++ /dev/null @@ -1,42 +0,0 @@ -package edu.ucdavis.earlybird; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Request location ONCE per WAKE_PERIOD_IN_MILLI. - */ -public class UCDService extends Service { - - public static final String ACTION_GET_LOCATION = "edu.ucdavis.earlybird.GET_LOCATION"; - private AlarmManager mAlarmManager; - private PendingIntent uploadIntent; - - @Override - public IBinder onBind(final Intent intent) { - throw new IllegalStateException("Not implemented."); - } - - @Override - public void onCreate() { - super.onCreate(); - - ProfilingUtil.log(this, "onCreate"); - mAlarmManager = (AlarmManager) getSystemService(Service.ALARM_SERVICE); - - // Upload Service - final Intent i = new Intent(UploadReceiver.ACTION_UPLOAD_PROFILE); - uploadIntent = PendingIntent.getBroadcast(this, 0, i, 0); - mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 12 * 60 * 60 * 1000, uploadIntent); - } - - @Override - public void onDestroy() { - mAlarmManager.cancel(uploadIntent); - super.onDestroy(); - } - -} diff --git a/twidere/src/main/java/edu/ucdavis/earlybird/UploadReceiver.java b/twidere/src/main/java/edu/ucdavis/earlybird/UploadReceiver.java deleted file mode 100644 index be3077cd6..000000000 --- a/twidere/src/main/java/edu/ucdavis/earlybird/UploadReceiver.java +++ /dev/null @@ -1,27 +0,0 @@ -package edu.ucdavis.earlybird; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.wifi.WifiManager; - -import org.mariotaku.twidere.util.Utils; - -public class UploadReceiver extends BroadcastReceiver { - - public static final String ACTION_UPLOAD_PROFILE = "edu.ucdavis.earlybird.UPLOAD_PROFILE"; - - @Override - public void onReceive(final Context context, final Intent intent) { - final String action = intent.getAction(); - final boolean isWifi = Utils.isOnWifi(context.getApplicationContext()); - final boolean isCharging = ProfilingUtil.isCharging(context.getApplicationContext()); - if (WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.equals(action)) { - final boolean wifi = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false); - ProfilingUtil.profile(context, ProfilingUtil.FILE_NAME_WIFI, wifi ? "connected" : "disconnected"); - } - if (isWifi && isCharging) { - new UploadTask(context).execute(); - } - } -} diff --git a/twidere/src/main/java/edu/ucdavis/earlybird/UploadTask.java b/twidere/src/main/java/edu/ucdavis/earlybird/UploadTask.java deleted file mode 100644 index 3c770d4e9..000000000 --- a/twidere/src/main/java/edu/ucdavis/earlybird/UploadTask.java +++ /dev/null @@ -1,146 +0,0 @@ -package edu.ucdavis.earlybird; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.provider.Settings.Secure; - -import org.mariotaku.restfu.annotation.method.POST; -import org.mariotaku.restfu.http.RestHttpClient; -import org.mariotaku.restfu.http.RestHttpRequest; -import org.mariotaku.restfu.http.RestHttpResponse; -import org.mariotaku.restfu.http.mime.FileTypedData; -import org.mariotaku.restfu.http.mime.MultipartTypedBody; -import org.mariotaku.twidere.util.TwitterAPIFactory; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -import static org.mariotaku.twidere.util.Utils.copyStream; - -public class UploadTask extends AsyncTask { - - private static final String LAST_UPLOAD_DATE = "last_upload_time"; - private static final double MILLSECS_HALF_DAY = 1000 * 60 * 60 * 12; - - private final String device_id; - private final Context context; - - private final RestHttpClient client; - - private static final String PROFILE_SERVER_URL = "http://weik.metaisle.com/profiles"; - - // private static final String PROFILE_SERVER_URL = - // "http://192.168.0.105:3000/profiles"; - - public UploadTask(final Context context) { - this.context = context; - this.client = TwitterAPIFactory.getDefaultHttpClient(context); - device_id = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID); - } - - public void uploadMultipart(final String url, final File file) { - final String app_root = file.getParent(); - final File tmp_dir = new File(app_root + "/tmp"); - if (!tmp_dir.exists()) { - if (!tmp_dir.mkdirs()) { - ProfilingUtil.log(context, "cannot create tmp, do nothing."); - return; - } - } - final File tmp = new File(tmp_dir, file.getName()); - file.renameTo(tmp); - - try { - - final RestHttpRequest.Builder builder = new RestHttpRequest.Builder(); - builder.url(PROFILE_SERVER_URL); - builder.method(POST.METHOD); - final MultipartTypedBody body = new MultipartTypedBody(); - body.add("upload", new FileTypedData(tmp)); - builder.body(body); - final RestHttpResponse response = client.execute(builder.build()); - - // Responses from the server (code and message) - final int serverResponseCode = response.getStatus(); - - ProfilingUtil.log(context, "server response code " + serverResponseCode); - - if (serverResponseCode / 100 == 2) { - tmp.delete(); - } else { - putBackProfile(context, tmp, file); - } - - } catch (final IOException e) { - e.printStackTrace(); - putBackProfile(context, tmp, file); - } - } - - @Override - protected Object doInBackground(final Object... params) { - - final SharedPreferences prefs = context.getSharedPreferences("ucd_data_profiling", Context.MODE_PRIVATE); - - if (prefs.contains(LAST_UPLOAD_DATE)) { - final long lastUpload = prefs.getLong(LAST_UPLOAD_DATE, System.currentTimeMillis()); - final double deltaDays = (System.currentTimeMillis() - lastUpload) / (MILLSECS_HALF_DAY * 2); - if (deltaDays < 1) { - ProfilingUtil.log(context, "Uploaded less than 1 day ago."); - return null; - } - } - - final File root = context.getFilesDir(); - final File[] files = root.listFiles(new CSVFileFilter()); - - uploadToNode(files); - prefs.edit().putLong(LAST_UPLOAD_DATE, System.currentTimeMillis()).apply(); - return null; - } - - private boolean uploadToNode(final File... files) { - for (final File file : files) { - if (file.isDirectory()) { - continue; - } - final String url = PROFILE_SERVER_URL + "/" + device_id + "/" - + file.getName().replaceFirst("[.][^.]+$", ""); - ProfilingUtil.log(context, url); - uploadMultipart(url, file); - } - return false; - } - - public static void putBackProfile(final Context context, final File tmp, final File profile) { - boolean success; - if (profile.exists()) { - try { - final FileOutputStream os = new FileOutputStream(tmp, true); - final FileInputStream is = new FileInputStream(profile); - copyStream(is, os); - is.close(); - os.close(); - success = true; - } catch (final IOException e) { - e.printStackTrace(); - success = false; - } - - if (success && tmp.renameTo(profile) && tmp.delete()) { - ProfilingUtil.log(context, "put profile back success"); - } else { - ProfilingUtil.log(context, "put profile back failed"); - } - } else { - if (tmp.renameTo(profile)) { - ProfilingUtil.log(context, "put profile back success"); - } else { - ProfilingUtil.log(context, "put profile back failed"); - } - } - } -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java index fd1548bd0..ab18a63a8 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java @@ -50,7 +50,6 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; import org.mariotaku.twidere.util.AsyncTaskUtils; import org.mariotaku.twidere.util.OAuthPasswordAuthenticator; import org.mariotaku.twidere.util.TwitterAPIFactory; -import org.mariotaku.twidere.util.TwitterAPIUtils; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; @@ -238,7 +237,7 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity { consumerSecret = defConsumerSecret; } try { - final Endpoint endpoint = new Endpoint(TwitterAPIUtils.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", "oauth")); + final Endpoint endpoint = new Endpoint(TwitterAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", "oauth")); final Authorization auth = new OAuthAuthorization(consumerKey, consumerSecret); final TwitterOAuth twitter = TwitterAPIFactory.getInstance(mActivity, endpoint, auth, TwitterOAuth.class); return twitter.getRequestToken(OAUTH_CALLBACK_OOB); diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java index 8e34940ab..b8dbe5125 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java @@ -87,6 +87,7 @@ import org.mariotaku.twidere.model.SupportTabSpec; import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; import org.mariotaku.twidere.provider.TwidereDataStore.Mentions; import org.mariotaku.twidere.provider.TwidereDataStore.Statuses; +import org.mariotaku.twidere.service.StreamingService; import org.mariotaku.twidere.util.AsyncTaskUtils; import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.CustomTabUtils; @@ -120,7 +121,6 @@ import java.util.Map.Entry; import edu.tsinghua.spice.Utilies.NetworkStateUtil; import edu.tsinghua.spice.Utilies.SpiceProfilingUtil; -import edu.ucdavis.earlybird.ProfilingUtil; import static org.mariotaku.twidere.util.CompareUtils.classEquals; import static org.mariotaku.twidere.util.Utils.cleanDatabasesByItemLimit; @@ -428,6 +428,8 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen final int initialTabPosition = handleIntent(intent, savedInstanceState == null); setTabPosition(initialTabPosition); + + startService(new Intent(this, StreamingService.class)); } @Override @@ -440,8 +442,6 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen final Bus bus = TwidereApplication.getInstance(this).getMessageBus(); assert bus != null; bus.register(this); - // UCD - ProfilingUtil.profile(this, ProfilingUtil.FILE_NAME_APP, "App onStart"); // spice SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_APP, "App Launch" + "," + Build.MODEL + "," + "mediaPreview=" + mPreferences.getBoolean(KEY_MEDIA_PREVIEW, false)); @@ -480,8 +480,6 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen mPreferences.edit().putInt(KEY_SAVED_TAB_POSITION, mViewPager.getCurrentItem()).apply(); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONSTOP)); - // UCD - ProfilingUtil.profile(this, ProfilingUtil.FILE_NAME_APP, "App onStop"); // spice SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_APP, "App Stop"); SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_ONLAUNCH, "App Stop" + "," + NetworkStateUtil.getConnectedType(this) + "," + Build.MODEL); @@ -621,6 +619,9 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen @Override protected void onDestroy() { + + stopService(new Intent(this, StreamingService.class)); + // Delete unused items in databases. cleanDatabasesByItemLimit(this); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONDESTROY)); diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java index 1c84b7b6e..cdfbe70db 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java @@ -91,7 +91,6 @@ import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.TwidereActionModeForChildListener; import org.mariotaku.twidere.util.TwidereColorUtils; import org.mariotaku.twidere.util.TwitterAPIFactory; -import org.mariotaku.twidere.util.TwitterAPIUtils; import org.mariotaku.twidere.util.support.ViewSupport; import org.mariotaku.twidere.util.support.view.ViewOutlineProviderCompat; import org.mariotaku.twidere.view.iface.TintedStatusLayout; @@ -599,7 +598,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList protected SignInResponse doInBackground(final Object... params) { try { final String versionSuffix = noVersionSuffix ? null : "1.1"; - final Endpoint endpoint = new Endpoint(TwitterAPIUtils.getApiUrl(apiUrlFormat, "api", versionSuffix)); + final Endpoint endpoint = new Endpoint(TwitterAPIFactory.getApiUrl(apiUrlFormat, "api", versionSuffix)); final TwitterOAuth oauth = TwitterAPIFactory.getInstance(context, endpoint, new OAuthAuthorization(consumerKey.getOauthToken(), consumerKey.getOauthTokenSecret()), TwitterOAuth.class); final OAuthToken accessToken = oauth.getAccessToken(requestToken, oauthVerifier); @@ -684,7 +683,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList private SignInResponse authBasic() throws TwitterException { final String versionSuffix = noVersionSuffix ? null : "1.1"; - final Endpoint endpoint = new Endpoint(TwitterAPIUtils.getApiUrl(apiUrlFormat, "api", versionSuffix)); + final Endpoint endpoint = new Endpoint(TwitterAPIFactory.getApiUrl(apiUrlFormat, "api", versionSuffix)); final Authorization auth = new BasicAuthorization(username, password); final Twitter twitter = TwitterAPIFactory.getInstance(context, endpoint, auth, Twitter.class); final User user = twitter.verifyCredentials(); @@ -698,9 +697,9 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList private SignInResponse authOAuth() throws AuthenticationException, TwitterException { String endpointUrl, signEndpointUrl; - endpointUrl = TwitterAPIUtils.getApiUrl(apiUrlFormat, "api", null); + endpointUrl = TwitterAPIFactory.getApiUrl(apiUrlFormat, "api", null); if (!sameOAuthSigningUrl) { - signEndpointUrl = TwitterAPIUtils.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", null); + signEndpointUrl = TwitterAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", null); } else { signEndpointUrl = endpointUrl; } @@ -712,9 +711,9 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList final long userId = accessToken.getUserId(); if (userId <= 0) return new SignInResponse(false, false, null); final String versionSuffix = noVersionSuffix ? null : "1.1"; - endpointUrl = TwitterAPIUtils.getApiUrl(apiUrlFormat, "api", versionSuffix); + endpointUrl = TwitterAPIFactory.getApiUrl(apiUrlFormat, "api", versionSuffix); if (!sameOAuthSigningUrl) { - signEndpointUrl = TwitterAPIUtils.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", versionSuffix); + signEndpointUrl = TwitterAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", versionSuffix); } else { signEndpointUrl = endpointUrl; } @@ -730,7 +729,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList private SignInResponse authTwipOMode() throws TwitterException { final String versionSuffix = noVersionSuffix ? null : "1.1"; - final Endpoint endpoint = new Endpoint(TwitterAPIUtils.getApiUrl(apiUrlFormat, "api", versionSuffix)); + final Endpoint endpoint = new Endpoint(TwitterAPIFactory.getApiUrl(apiUrlFormat, "api", versionSuffix)); final Authorization auth = new EmptyAuthorization(); final Twitter twitter = TwitterAPIFactory.getInstance(context, endpoint, auth, Twitter.class); final User user = twitter.verifyCredentials(); @@ -742,7 +741,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList private SignInResponse authxAuth() throws TwitterException { final String versionSuffix = noVersionSuffix ? null : "1.1"; - final Endpoint endpoint = new Endpoint(TwitterAPIUtils.getApiUrl(apiUrlFormat, "api", versionSuffix)); + final Endpoint endpoint = new Endpoint(TwitterAPIFactory.getApiUrl(apiUrlFormat, "api", versionSuffix)); OAuthAuthorization auth = new OAuthAuthorization(consumerKey.getOauthToken(), consumerKey.getOauthTokenSecret()); final TwitterOAuth oauth = TwitterAPIFactory.getInstance(context, endpoint, auth, TwitterOAuth.class); final OAuthToken accessToken = oauth.getAccessToken(username, password, TwitterOAuth.XAuthMode.CLIENT); diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/TwitterUserStream.java b/twidere/src/main/java/org/mariotaku/twidere/api/twitter/TwitterUserStream.java similarity index 100% rename from twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/TwitterUserStream.java rename to twidere/src/main/java/org/mariotaku/twidere/api/twitter/TwitterUserStream.java diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java b/twidere/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java similarity index 57% rename from twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java rename to twidere/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java index b651a0f84..ba82faa9e 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java +++ b/twidere/src/main/java/org/mariotaku/twidere/api/twitter/UserStreamCallback.java @@ -19,6 +19,8 @@ package org.mariotaku.twidere.api.twitter; +import android.util.Log; + import com.bluelinelabs.logansquare.LoganSquare; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -42,6 +44,8 @@ import java.io.InputStreamReader; */ public abstract class UserStreamCallback implements RawCallback { + private boolean connected; + private boolean disconnected; @Override @@ -54,78 +58,93 @@ public abstract class UserStreamCallback implements RawCallback { } final ObjectMapper mapper = new ObjectMapper(LoganSquare.JSON_FACTORY); final CRLFLineReader reader = new CRLFLineReader(new InputStreamReader(response.getBody().stream(), "UTF-8")); - for (String line; (line = reader.readLine()) != null && !disconnected; ) { - if (line.isEmpty()) continue; - JsonNode rootNode = mapper.readTree(line); - switch (JSONObjectType.determine(rootNode)) { - case SENDER: { - break; + try { + for (String line; (line = reader.readLine()) != null && !disconnected; ) { + if (!connected) { + onConnected(); + connected = true; } - case STATUS: { - onStatus(LoganSquare.mapperFor(Status.class).parse(rootNode.traverse())); - break; + if (line.isEmpty()) continue; + JsonNode rootNode = mapper.readTree(line); + switch (JSONObjectType.determine(rootNode)) { + case SENDER: { + break; + } + case STATUS: { + onStatus(LoganSquare.mapperFor(Status.class).parse(rootNode.traverse())); + break; + } + case DIRECT_MESSAGE: { + onDirectMessage(LoganSquare.mapperFor(DirectMessage.class).parse(rootNode.traverse())); + break; + } + case DELETE: { + break; + } + case LIMIT: + break; + case STALL_WARNING: + break; + case SCRUB_GEO: + break; + case FRIENDS: + break; + case FAVORITE: { + onFavorite(parse(User.class, rootNode.get("source")), + parse(User.class, rootNode.get("target")), + parse(Status.class, rootNode.get("target_object"))); + break; + } + case UNFAVORITE: { + onUnfavorite(parse(User.class, rootNode.get("source")), + parse(User.class, rootNode.get("target")), + parse(Status.class, rootNode.get("target_object"))); + break; + } + case FOLLOW: + break; + case UNFOLLOW: + break; + case USER_LIST_MEMBER_ADDED: + break; + case USER_LIST_MEMBER_DELETED: + break; + case USER_LIST_SUBSCRIBED: + break; + case USER_LIST_UNSUBSCRIBED: + break; + case USER_LIST_CREATED: + break; + case USER_LIST_UPDATED: + break; + case USER_LIST_DESTROYED: + break; + case USER_UPDATE: + break; + case USER_DELETE: + break; + case USER_SUSPEND: + break; + case BLOCK: + break; + case UNBLOCK: + break; + case DISCONNECTION: + break; + case UNKNOWN: + break; } - case DIRECT_MESSAGE: { - onDirectMessage(LoganSquare.mapperFor(DirectMessage.class).parse(rootNode.traverse())); - break; - } - case DELETE: { - break; - } - case LIMIT: - break; - case STALL_WARNING: - break; - case SCRUB_GEO: - break; - case FRIENDS: - break; - case FAVORITE: { - onFavorite(parse(User.class, rootNode.get("source")), - parse(User.class, rootNode.get("target")), - parse(Status.class, rootNode.get("target_object"))); - break; - } - case UNFAVORITE: - break; - case FOLLOW: - break; - case UNFOLLOW: - break; - case USER_LIST_MEMBER_ADDED: - break; - case USER_LIST_MEMBER_DELETED: - break; - case USER_LIST_SUBSCRIBED: - break; - case USER_LIST_UNSUBSCRIBED: - break; - case USER_LIST_CREATED: - break; - case USER_LIST_UPDATED: - break; - case USER_LIST_DESTROYED: - break; - case USER_UPDATE: - break; - case USER_DELETE: - break; - case USER_SUSPEND: - break; - case BLOCK: - break; - case UNBLOCK: - break; - case DISCONNECTION: - break; - case UNKNOWN: - break; } + } catch (IOException e) { + onException(e); + } finally { + Log.d("Twidere.Stream", "Cleaning up..."); + reader.close(); + response.close(); } - reader.close(); - response.close(); } + private static T parse(final Class cls, final JsonNode json) throws IOException { return LoganSquare.mapperFor(cls).parse(json.traverse()); } @@ -139,6 +158,8 @@ public abstract class UserStreamCallback implements RawCallback { disconnected = true; } + public abstract void onConnected(); + public abstract void onBlock(User source, User blockedUser); public abstract void onDeletionNotice(long directMessageId, long userId); diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/util/CRLFLineReader.java b/twidere/src/main/java/org/mariotaku/twidere/api/twitter/util/CRLFLineReader.java similarity index 100% rename from twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/util/CRLFLineReader.java rename to twidere/src/main/java/org/mariotaku/twidere/api/twitter/util/CRLFLineReader.java diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/util/JSONObjectType.java b/twidere/src/main/java/org/mariotaku/twidere/api/twitter/util/JSONObjectType.java similarity index 100% rename from twidere.component.common/src/main/java/org/mariotaku/twidere/api/twitter/util/JSONObjectType.java rename to twidere/src/main/java/org/mariotaku/twidere/api/twitter/util/JSONObjectType.java diff --git a/twidere/src/main/java/org/mariotaku/twidere/app/TwidereApplication.java b/twidere/src/main/java/org/mariotaku/twidere/app/TwidereApplication.java index e5531d358..0ae72faab 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/app/TwidereApplication.java +++ b/twidere/src/main/java/org/mariotaku/twidere/app/TwidereApplication.java @@ -55,6 +55,7 @@ import org.mariotaku.twidere.activity.MainHondaJOJOActivity; import org.mariotaku.twidere.service.RefreshService; import org.mariotaku.twidere.util.AsyncTaskManager; import org.mariotaku.twidere.util.AsyncTwitterWrapper; +import org.mariotaku.twidere.util.DebugModeUtils; import org.mariotaku.twidere.util.ErrorLogger; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; import org.mariotaku.twidere.util.MediaLoaderWrapper; @@ -73,7 +74,6 @@ import org.mariotaku.twidere.util.net.TwidereHostAddressResolver; import java.io.File; import edu.tsinghua.spice.SpiceService; -import edu.ucdavis.earlybird.UCDService; import static org.mariotaku.twidere.util.Utils.getBestCacheDir; import static org.mariotaku.twidere.util.Utils.getInternalCacheDir; @@ -236,6 +236,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants StrictModeUtils.detectAllVmPolicy(); } super.onCreate(); + initDebugMode(); initBugReport(); mDefaultUserAgent = UserAgentUtils.getDefaultUserAgentString(this); mHandler = new Handler(); @@ -269,6 +270,10 @@ public class TwidereApplication extends MultiDexApplication implements Constants reloadConnectivitySettings(); } + private void initDebugMode() { + DebugModeUtils.initForApplication(this); + } + private void initBugReport() { ACRA.init(this); ErrorLogger.setEnabled(BuildConfig.DEBUG); @@ -313,7 +318,6 @@ public class TwidereApplication extends MultiDexApplication implements Constants || KEY_PROXY_PORT.equals(key)) { reloadConnectivitySettings(); } else if (KEY_USAGE_STATISTICS.equals(key)) { - stopService(new Intent(this, UCDService.class)); //spice stopService(new Intent(this, SpiceService.class)); startUsageStatisticsServiceIfNeeded(this); diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.java index d98e12a50..261ebc778 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/AccountRefreshSettingsFragment.java @@ -19,6 +19,8 @@ package org.mariotaku.twidere.fragment; +import android.support.annotation.Nullable; + import org.mariotaku.twidere.R; public class AccountRefreshSettingsFragment extends BaseAccountPreferenceFragment { @@ -34,7 +36,8 @@ public class AccountRefreshSettingsFragment extends BaseAccountPreferenceFragmen } @Override + @Nullable protected String getSwitchPreferenceKey() { - return KEY_AUTO_REFRESH; + return null; } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/BaseAccountPreferenceFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/BaseAccountPreferenceFragment.java index 953dc2a80..43856c4bd 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/BaseAccountPreferenceFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/BaseAccountPreferenceFragment.java @@ -28,6 +28,8 @@ import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; +import android.support.annotation.Nullable; +import android.text.TextUtils; import android.view.Menu; import android.view.MenuInflater; import android.view.View; @@ -78,12 +80,15 @@ public abstract class BaseAccountPreferenceFragment extends PreferenceFragment i @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { - inflater.inflate(R.menu.menu_switch_preference, menu); - final View actionView = menu.findItem(MENU_TOGGLE).getActionView(); - final CompoundButton toggle = (CompoundButton) actionView.findViewById(android.R.id.toggle); - final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - toggle.setOnCheckedChangeListener(this); - toggle.setChecked(prefs.getBoolean(getSwitchPreferenceKey(), getSwitchPreferenceDefault())); + final String switchKey = getSwitchPreferenceKey(); + if (!TextUtils.isEmpty(switchKey)) { + inflater.inflate(R.menu.menu_switch_preference, menu); + final View actionView = menu.findItem(MENU_TOGGLE).getActionView(); + final CompoundButton toggle = (CompoundButton) actionView.findViewById(android.R.id.toggle); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + toggle.setOnCheckedChangeListener(this); + toggle.setChecked(prefs.getBoolean(switchKey, getSwitchPreferenceDefault())); + } super.onCreateOptionsMenu(menu, inflater); } @@ -104,6 +109,7 @@ public abstract class BaseAccountPreferenceFragment extends PreferenceFragment i protected abstract boolean getSwitchPreferenceDefault(); + @Nullable protected abstract String getSwitchPreferenceKey(); private void updatePreferenceScreen() { diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AccountsDashboardFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AccountsDashboardFragment.java index 113cadf4b..1eff07098 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AccountsDashboardFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AccountsDashboardFragment.java @@ -136,6 +136,7 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo private ActionMenuView mAccountsToggleMenu; private View mAccountProfileContainer; private View mNoAccountContainer; + private ActionMenuView mActionMenuView; private Context mThemedContext; private MediaLoaderWrapper mImageLoader; @@ -313,30 +314,6 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo break; } } - } else if (adapter instanceof AppMenuAdapter) { - if (!(item instanceof OptionItem)) return; - final OptionItem option = (OptionItem) item; - switch (option.id) { - case MENU_ACCOUNTS: { - Utils.openAccountsManager(getActivity()); - break; - } - case MENU_DRAFTS: { - Utils.openDrafts(getActivity()); - break; - } - case MENU_FILTERS: { - Utils.openFilters(getActivity()); - break; - } - case MENU_SETTINGS: { - final Intent intent = new Intent(getActivity(), SettingsActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivityForResult(intent, REQUEST_SETTINGS); - break; - } - } - closeAccountsDrawer(); } } @@ -431,11 +408,41 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo mAdapter.addView(mAccountSelectorView, true); mAdapter.addAdapter(mAccountOptionsAdapter); - mAdapter.addView(mAppMenuSectionView, false); - mAdapter.addAdapter(mAppMenuAdapter); +// mAdapter.addView(mAppMenuSectionView, false); +// mAdapter.addAdapter(mAppMenuAdapter); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(this); mPreferences.registerOnSharedPreferenceChangeListener(this); + + menuInflater.inflate(R.menu.menu_dashboard, mActionMenuView.getMenu()); + + mActionMenuView.setOnMenuItemClickListener(new OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(final MenuItem item) { + switch (item.getItemId()) { + case MENU_ACCOUNTS: { + Utils.openAccountsManager(getActivity()); + return true; + } + case MENU_DRAFTS: { + Utils.openDrafts(getActivity()); + return true; + } + case MENU_FILTERS: { + Utils.openFilters(getActivity()); + return true; + } + case MENU_SETTINGS: { + final Intent intent = new Intent(getActivity(), SettingsActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivityForResult(intent, REQUEST_SETTINGS); + return true; + } + } + return false; + } + }); + ThemeUtils.resetCheatSheet(mActionMenuView); getLoaderManager().initLoader(0, null, this); } @@ -448,6 +455,7 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo public void onBaseViewCreated(View view, Bundle savedInstanceState) { super.onBaseViewCreated(view, savedInstanceState); mListView = (ListView) view.findViewById(android.R.id.list); + mActionMenuView = (ActionMenuView) view.findViewById(R.id.dashboard_menu); } @Override @@ -849,7 +857,7 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo private final int mActionIconColor; public OptionItemsAdapter(final Context context) { - super(context, R.layout.list_item_menu); + super(context, R.layout.list_item_dashboard_menu); mActionIconColor = ThemeUtils.getThemeForegroundColor(context); } diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java index 7b2df7280..a8e20e9be 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java @@ -19,6 +19,7 @@ package org.mariotaku.twidere.fragment.support; +import android.app.NotificationManager; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; @@ -295,6 +296,16 @@ public class DirectMessagesFragment extends AbsContentRecyclerViewFragment accounts) { removeAll(); for (final ParcelableAccount account : accounts) { - final AccountItemPreference preference = new AccountItemPreference(getContext(), account, mSwitchKey, - mSwitchDefault); + final AccountItemPreference preference = new AccountItemPreference(getContext(), account, + mSwitchKey, mSwitchDefault); setupPreference(preference, account); addPreference(preference); } @@ -96,39 +93,23 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen protected abstract void setupPreference(AccountItemPreference preference, ParcelableAccount account); public static final class AccountItemPreference extends Preference implements ImageLoadingListener, - OnCheckedChangeListener, OnSharedPreferenceChangeListener, OnPreferenceClickListener, OnClickListener { + OnSharedPreferenceChangeListener { private final ParcelableAccount mAccount; private final SharedPreferences mSwitchPreference; private final MediaLoaderWrapper mImageLoader; - private final String mSwitchKey; - private final boolean mSwitchDefault; - private CompoundButton mToggle; - public AccountItemPreference(final Context context, final ParcelableAccount account, final String switchKey, final boolean switchDefault) { super(context); - setWidgetLayoutResource(R.layout.preference_widget_account_preference_item); - setOnPreferenceClickListener(this); final String switchPreferenceName = ACCOUNT_PREFERENCES_NAME_PREFIX + account.account_id; mAccount = account; mSwitchPreference = context.getSharedPreferences(switchPreferenceName, Context.MODE_PRIVATE); final TwidereApplication app = TwidereApplication.getInstance(context); mImageLoader = app.getMediaLoaderWrapper(); - mSwitchKey = switchKey; - mSwitchDefault = switchDefault; mSwitchPreference.registerOnSharedPreferenceChangeListener(this); } - @Override - public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { - if (mSwitchKey == null) return; - final SharedPreferences.Editor editor = mSwitchPreference.edit(); - editor.putBoolean(mSwitchKey, isChecked); - editor.apply(); - } - @Override public void onLoadingCancelled(final String imageUri, final View view) { // setIcon(R.drawable.ic_profile_image_default); @@ -164,16 +145,6 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen mImageLoader.loadProfileImage(mAccount.profile_image_url, this); } - @Override - protected View onCreateView(ViewGroup parent) { - final View view = super.onCreateView(parent); - view.findViewById(R.id.settings).setOnClickListener(this); - final CompoundButton toggle = (CompoundButton) view.findViewById(android.R.id.toggle); - toggle.setOnCheckedChangeListener(this); - mToggle = toggle; - return view; - } - @Override protected void onBindView(@NonNull final View view) { super.onBindView(view); @@ -190,26 +161,6 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen if (summaryView instanceof TextView) { ((TextView) summaryView).setSingleLine(true); } - final CompoundButton toggle = (CompoundButton) view.findViewById(android.R.id.toggle); - if (mSwitchKey != null) { - toggle.setChecked(mSwitchPreference.getBoolean(mSwitchKey, mSwitchDefault)); - } - } - - @Override - public boolean onPreferenceClick(Preference preference) { - if (mToggle != null) { - mToggle.toggle(); - } - return true; - } - - @Override - public void onClick(View v) { - final Context context = getContext(); - if (!(context instanceof PreferenceActivity)) return; - final PreferenceActivity activity = (PreferenceActivity) context; - activity.startPreferencePanel(getFragment(), getExtras(), getTitleRes(), getTitle(), null, 0); } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/preference/AutoFixSwitchPreference.java b/twidere/src/main/java/org/mariotaku/twidere/preference/AutoFixSwitchPreference.java index 0531d8b90..79f234c4d 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/preference/AutoFixSwitchPreference.java +++ b/twidere/src/main/java/org/mariotaku/twidere/preference/AutoFixSwitchPreference.java @@ -28,8 +28,6 @@ import org.jraf.android.backport.switchwidget.SwitchPreference; public class AutoFixSwitchPreference extends SwitchPreference { - private View mCachedView; - public AutoFixSwitchPreference(final Context context) { super(context); } diff --git a/twidere/src/main/java/org/mariotaku/twidere/preference/DarkLightThemeTogglePreference.java b/twidere/src/main/java/org/mariotaku/twidere/preference/DarkLightThemeTogglePreference.java new file mode 100644 index 000000000..4c3e1e48a --- /dev/null +++ b/twidere/src/main/java/org/mariotaku/twidere/preference/DarkLightThemeTogglePreference.java @@ -0,0 +1,55 @@ +/* + * 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.mariotaku.twidere.preference; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.AttributeSet; + +import org.jraf.android.backport.switchwidget.SwitchPreference; +import org.mariotaku.twidere.Constants; +import org.mariotaku.twidere.R; +import org.mariotaku.twidere.util.ThemeUtils; + +public class DarkLightThemeTogglePreference extends SwitchPreference implements Constants { + + public DarkLightThemeTogglePreference(final Context context) { + this(context, null); + } + + public DarkLightThemeTogglePreference(final Context context, final AttributeSet attrs) { + this(context, attrs, R.attr.asb_switchPreferenceStyle); + } + + public DarkLightThemeTogglePreference(final Context context, final AttributeSet attrs, final int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected boolean getPersistedBoolean(final boolean defaultReturnValue) { + final SharedPreferences preferences = getSharedPreferences(); + return ThemeUtils.isDarkTheme(getPersistedString(VALUE_THEME_NAME_TWIDERE)); + } + + @Override + protected boolean persistBoolean(final boolean value) { + return persistString(value ? VALUE_THEME_NAME_DARK : VALUE_THEME_NAME_TWIDERE); + } +} diff --git a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/StreamingService.java b/twidere/src/main/java/org/mariotaku/twidere/service/StreamingService.java similarity index 68% rename from twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/StreamingService.java rename to twidere/src/main/java/org/mariotaku/twidere/service/StreamingService.java index 30d96219a..62eacdac1 100644 --- a/twidere.extension.streaming/src/main/java/org/mariotaku/twidere/extension/streaming/StreamingService.java +++ b/twidere/src/main/java/org/mariotaku/twidere/service/StreamingService.java @@ -1,6 +1,5 @@ -package org.mariotaku.twidere.extension.streaming; +package org.mariotaku.twidere.service; -import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; @@ -13,14 +12,19 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.IBinder; -import android.preference.PreferenceManager; +import android.support.v4.app.NotificationCompat; +import android.support.v4.util.LongSparseArray; import android.util.Log; -import android.widget.Toast; import org.mariotaku.restfu.http.Authorization; +import org.mariotaku.restfu.http.ContentType; import org.mariotaku.restfu.http.Endpoint; -import org.mariotaku.twidere.Twidere; -import org.mariotaku.twidere.TwidereSharedPreferences; +import org.mariotaku.restfu.http.RestHttpResponse; +import org.mariotaku.restfu.http.mime.TypedData; +import org.mariotaku.twidere.BuildConfig; +import org.mariotaku.twidere.Constants; +import org.mariotaku.twidere.R; +import org.mariotaku.twidere.activity.SettingsActivity; import org.mariotaku.twidere.api.twitter.TwitterException; import org.mariotaku.twidere.api.twitter.TwitterUserStream; import org.mariotaku.twidere.api.twitter.UserStreamCallback; @@ -30,7 +34,7 @@ import org.mariotaku.twidere.api.twitter.model.StatusDeletionNotice; import org.mariotaku.twidere.api.twitter.model.User; import org.mariotaku.twidere.api.twitter.model.UserList; import org.mariotaku.twidere.api.twitter.model.Warning; -import org.mariotaku.twidere.extension.streaming.util.Utils; +import org.mariotaku.twidere.model.AccountPreferences; import org.mariotaku.twidere.model.ParcelableAccount; import org.mariotaku.twidere.model.ParcelableCredentials; import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; @@ -38,19 +42,21 @@ import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages; import org.mariotaku.twidere.provider.TwidereDataStore.Mentions; import org.mariotaku.twidere.provider.TwidereDataStore.Statuses; import org.mariotaku.twidere.util.ContentValuesCreator; +import org.mariotaku.twidere.util.SharedPreferencesWrapper; import org.mariotaku.twidere.util.TwidereArrayUtils; -import org.mariotaku.twidere.util.TwitterAPIUtils; +import org.mariotaku.twidere.util.TwitterAPIFactory; +import org.mariotaku.twidere.util.Utils; -import java.lang.ref.WeakReference; -import java.util.ArrayList; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; import java.util.List; -public class StreamingService extends Service implements Constants, PrivateConstants { +public class StreamingService extends Service implements Constants { private static final int NOTIFICATION_SERVICE_STARTED = 1; - private static final int NOTIFICATION_REQUEST_PERMISSION = 2; - private final List> mTwitterInstances = new ArrayList<>(); + private final LongSparseArray mCallbacks = new LongSparseArray<>(); private ContentResolver mResolver; private SharedPreferences mPreferences; @@ -86,11 +92,11 @@ public class StreamingService extends Service implements Constants, PrivateConst @Override public void onCreate() { super.onCreate(); - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); + mPreferences = SharedPreferencesWrapper.getInstance(this, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); mResolver = getContentResolver(); mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (BuildConfig.DEBUG) { - Log.d(LOGTAG, "Stream service started."); + Log.d(Constants.LOGTAG, "Stream service started."); } initStreaming(); mResolver.registerContentObserver(Accounts.CONTENT_URI, true, mAccountChangeObserver); @@ -101,103 +107,93 @@ public class StreamingService extends Service implements Constants, PrivateConst clearTwitterInstances(); mResolver.unregisterContentObserver(mAccountChangeObserver); if (BuildConfig.DEBUG) { - Log.d(LOGTAG, "Stream service stopped."); + Log.d(Constants.LOGTAG, "Stream service stopped."); } super.onDestroy(); } private void clearTwitterInstances() { - for (final WeakReference reference : mTwitterInstances) { - final TwidereUserStreamCallback twitter = reference.get(); - new Thread(new ShutdownStreamTwitterRunnable(twitter)).start(); + for (int i = 0, j = mCallbacks.size(); i < j; i++) { + new Thread(new ShutdownStreamTwitterRunnable(mCallbacks.valueAt(i))).start(); } - mTwitterInstances.clear(); + mCallbacks.clear(); mNotificationManager.cancel(NOTIFICATION_SERVICE_STARTED); } @SuppressWarnings("deprecation") private void initStreaming() { - if (!mPreferences.getBoolean(PREFERENCE_KEY_ENABLE_STREAMING, true)) return; - final boolean granted; - try { - granted = Twidere.isPermissionGranted(this); - } catch (final SecurityException e) { - stopSelf(); - return; - } - if (granted) { - final TwidereSharedPreferences prefs = Twidere.getSharedPreferences(this); - if (setTwitterInstances(prefs)) { - final Intent intent = new Intent(this, SettingsActivity.class); - final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); - final CharSequence contentTitle = getString(R.string.app_name); - final CharSequence contentText = getString(R.string.streaming_service_running); - final Notification notification = new Notification(); - notification.flags = Notification.FLAG_ONGOING_EVENT; - notification.icon = R.drawable.ic_stat_twidere; - notification.tickerText = getString(R.string.streaming_service_running); - notification.setLatestEventInfo(this, contentTitle, contentText, contentIntent); - mNotificationManager.notify(NOTIFICATION_SERVICE_STARTED, notification); - } else { - mNotificationManager.cancel(NOTIFICATION_SERVICE_STARTED); - } - } else { - final Intent intent = new Intent(this, SettingsActivity.class); - final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); - final CharSequence contentTitle = getString(R.string.app_name); - final CharSequence contentText = getString(R.string.request_permission); - final Notification notification = new Notification(); - notification.flags = Notification.FLAG_AUTO_CANCEL; - notification.icon = R.drawable.ic_stat_login; - notification.tickerText = getString(R.string.request_permission); - notification.setLatestEventInfo(this, contentTitle, contentText, contentIntent); - mNotificationManager.notify(NOTIFICATION_REQUEST_PERMISSION, notification); - } + if (!BuildConfig.DEBUG) return; + setTwitterInstances(); + updateStreamState(); } - - private boolean setTwitterInstances(final TwidereSharedPreferences prefs) { - if (prefs == null) return false; + private boolean setTwitterInstances() { final List accountsList = ParcelableAccount.getCredentialsList(this, true); - if (BuildConfig.DEBUG) { - Log.d(LOGTAG, "Setting up twitter stream instances"); + final long[] accountIds = new long[accountsList.size()]; + for (int i = 0, j = accountIds.length; i < j; i++) { + accountIds[i] = accountsList.get(i).account_id; } - mAccountIds = new long[accountsList.size()]; + final AccountPreferences[] activitedPreferences = AccountPreferences.getAccountPreferences(this, accountIds); + if (BuildConfig.DEBUG) { + Log.d(Constants.LOGTAG, "Setting up twitter stream instances"); + } + mAccountIds = accountIds; clearTwitterInstances(); + boolean result = false; for (int i = 0, j = accountsList.size(); i < j; i++) { + final AccountPreferences preferences = activitedPreferences[i]; + if (!preferences.isStreamingEnabled()) continue; final ParcelableCredentials account = accountsList.get(i); - final Endpoint endpoint = TwitterAPIUtils.getEndpoint(account, TwitterUserStream.class); - final Authorization authorization = TwitterAPIUtils.getAuthorization(account); - final TwitterUserStream twitter = Utils.getInstance(this, endpoint, authorization, TwitterUserStream.class); - final long account_id = account.account_id; - mAccountIds[i] = account_id; + final Endpoint endpoint = TwitterAPIFactory.getEndpoint(account, TwitterUserStream.class); + final Authorization authorization = TwitterAPIFactory.getAuthorization(account); + final TwitterUserStream twitter = TwitterAPIFactory.getInstance(this, endpoint, authorization, TwitterUserStream.class); final TwidereUserStreamCallback callback = new TwidereUserStreamCallback(this, account); - mTwitterInstances.add(new WeakReference<>(callback)); + mCallbacks.put(account.account_id, callback); new Thread() { @Override public void run() { twitter.getUserStream(callback); - Log.d(LOGTAG, "Stream disconnected"); + Log.d(Constants.LOGTAG, String.format("Stream %d disconnected", account.account_id)); + mCallbacks.remove(account.account_id); + updateStreamState(); } }.start(); + result |= true; + } + return result; + } + + private void updateStreamState() { + if (mCallbacks.size() > 0) { + final Intent intent = new Intent(this, SettingsActivity.class); + final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + final CharSequence contentTitle = getString(R.string.app_name); + final CharSequence contentText = getString(R.string.timeline_streaming_running); + final NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + builder.setOngoing(true); + builder.setSmallIcon(R.drawable.ic_stat_refresh); + builder.setContentTitle(contentTitle); + builder.setContentText(contentText); + builder.setContentIntent(contentIntent); + mNotificationManager.notify(NOTIFICATION_SERVICE_STARTED, builder.build()); + } else { + mNotificationManager.cancel(NOTIFICATION_SERVICE_STARTED); } - return true; } static class ShutdownStreamTwitterRunnable implements Runnable { - private final TwidereUserStreamCallback twitter; + private final UserStreamCallback callback; - ShutdownStreamTwitterRunnable(final TwidereUserStreamCallback twitter) { - this.twitter = twitter; + ShutdownStreamTwitterRunnable(final UserStreamCallback callback) { + this.callback = callback; } @Override public void run() { - if (twitter == null) return; - Log.d(LOGTAG, "Disconnecting stream"); - twitter.disconnect(); + if (callback == null) return; + Log.d(Constants.LOGTAG, "Disconnecting stream"); + callback.disconnect(); } } @@ -216,10 +212,15 @@ public class StreamingService extends Service implements Constants, PrivateConst resolver = context.getContentResolver(); } + @Override + public void onConnected() { + + } + @Override public void onBlock(final User source, final User blockedUser) { final String message = String.format("%s blocked %s", source.getScreenName(), blockedUser.getScreenName()); - Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + Log.d(LOGTAG, message); } @Override @@ -259,7 +260,7 @@ public class StreamingService extends Service implements Constants, PrivateConst final ContentValues values = ContentValuesCreator.createDirectMessage(directMessage, account.account_id, false); final Uri.Builder builder = DirectMessages.Inbox.CONTENT_URI.buildUpon(); - builder.appendQueryParameter(Twidere.QUERY_PARAM_NOTIFY, "true"); + builder.appendQueryParameter(QUERY_PARAM_NOTIFY, "true"); if (values != null) { resolver.insert(builder.build(), values); } @@ -271,8 +272,35 @@ public class StreamingService extends Service implements Constants, PrivateConst public void onException(final Throwable ex) { if (ex instanceof TwitterException) { Log.w(LOGTAG, String.format("Error %d", ((TwitterException) ex).getStatusCode()), ex); + final RestHttpResponse response = ((TwitterException) ex).getHttpResponse(); + if (response != null) { + try { + final TypedData body = response.getBody(); + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + body.writeTo(os); + final String charsetName; + if (body != null) { + final ContentType contentType = body.contentType(); + if (contentType != null) { + final Charset charset = contentType.getCharset(); + if (charset != null) { + charsetName = charset.name(); + } else { + charsetName = Charset.defaultCharset().name(); + } + } else { + charsetName = Charset.defaultCharset().name(); + } + } else { + charsetName = Charset.defaultCharset().name(); + } + Log.w(LOGTAG, os.toString(charsetName)); + } catch (IOException e) { + e.printStackTrace(); + } + } } else { - Log.w(LOGTAG, ex); + Log.w(Constants.LOGTAG, ex); } } @@ -280,14 +308,14 @@ public class StreamingService extends Service implements Constants, PrivateConst public void onFavorite(final User source, final User target, final Status favoritedStatus) { final String message = String.format("%s favorited %s's tweet: %s", source.getScreenName(), target.getScreenName(), favoritedStatus.getText()); - Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + Log.d(LOGTAG, message); } @Override public void onFollow(final User source, final User followedUser) { final String message = String .format("%s followed %s", source.getScreenName(), followedUser.getScreenName()); - Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + Log.d(LOGTAG, message); } @Override @@ -339,15 +367,14 @@ public class StreamingService extends Service implements Constants, PrivateConst public void onUnblock(final User source, final User unblockedUser) { final String message = String.format("%s unblocked %s", source.getScreenName(), unblockedUser.getScreenName()); - Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); + Log.d(LOGTAG, message); } @Override public void onUnfavorite(final User source, final User target, final Status unfavoritedStatus) { final String message = String.format("%s unfavorited %s's tweet: %s", source.getScreenName(), target.getScreenName(), unfavoritedStatus.getText()); - Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); - + Log.d(LOGTAG, message); } @Override diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/AsyncTwitterWrapper.java b/twidere/src/main/java/org/mariotaku/twidere/util/AsyncTwitterWrapper.java index ac98da8b6..78c3d68ed 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/AsyncTwitterWrapper.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/AsyncTwitterWrapper.java @@ -105,7 +105,6 @@ import java.util.concurrent.CopyOnWriteArraySet; import edu.tsinghua.spice.Utilies.SpiceProfilingUtil; import edu.tsinghua.spice.Utilies.TypeMappingUtil; -import edu.ucdavis.earlybird.ProfilingUtil; import static org.mariotaku.twidere.provider.TwidereDataStore.STATUSES_URIS; import static org.mariotaku.twidere.util.ContentValuesCreator.createDirectMessage; @@ -2207,8 +2206,6 @@ public class AsyncTwitterWrapper extends TwitterWrapper { rowsDeleted = 0; } countCur.close(); - // UCD - ProfilingUtil.profile(mContext, accountId, "Download tweets, " + TwidereArrayUtils.toString(statusIds, ',', true)); //spice SpiceProfilingUtil.profile(mContext, accountId, accountId + ",Refresh," + TwidereArrayUtils.toString(statusIds, ',', true)); //end diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/OnLinkClickHandler.java b/twidere/src/main/java/org/mariotaku/twidere/util/OnLinkClickHandler.java index da115fbb9..1bfb61d37 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/OnLinkClickHandler.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/OnLinkClickHandler.java @@ -33,7 +33,6 @@ import org.mariotaku.twidere.util.TwidereLinkify.OnLinkClickListener; import edu.tsinghua.spice.Utilies.SpiceProfilingUtil; import edu.tsinghua.spice.Utilies.TypeMappingUtil; -import edu.ucdavis.earlybird.ProfilingUtil; import static org.mariotaku.twidere.util.Utils.openStatus; import static org.mariotaku.twidere.util.Utils.openTweetSearch; @@ -57,8 +56,6 @@ public class OnLinkClickHandler implements OnLinkClickListener, Constants { final boolean sensitive, int start, int end) { if (manager != null && manager.isActive()) return; if (!isPrivateData()) { - // UCD - ProfilingUtil.profile(context, accountId, "Click, " + link + ", " + type); //spice SpiceProfilingUtil.profile(context, accountId, accountId + ",Visit," + link + "," + TypeMappingUtil.getLinkType(type)); //end diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/ThemeUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/ThemeUtils.java index 8f02fa962..57209a0a5 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/ThemeUtils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/ThemeUtils.java @@ -1111,6 +1111,10 @@ public class ThemeUtils implements Constants { return context.getResources().getColor(R.color.background_color_action_bar_dark); } + public static boolean isDarkTheme(final String name) { + return VALUE_THEME_NAME_DARK.equals(name); + } + public static final class ActionBarContextThemeWrapper extends android.support.v7.internal.view.ContextThemeWrapper { public ActionBarContextThemeWrapper(Context base, int themeres) { diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/TwitterAPIFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/TwitterAPIFactory.java index b2568312a..ebd256e1c 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/TwitterAPIFactory.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/TwitterAPIFactory.java @@ -2,19 +2,43 @@ package org.mariotaku.twidere.util; import android.content.Context; import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.SSLCertificateSocketFactory; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Pair; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.internal.Internal; +import org.mariotaku.restfu.ExceptionFactory; +import org.mariotaku.restfu.HttpRequestFactory; +import org.mariotaku.restfu.RequestInfoFactory; import org.mariotaku.restfu.RestAPIFactory; +import org.mariotaku.restfu.RestMethodInfo; +import org.mariotaku.restfu.RestRequestInfo; +import org.mariotaku.restfu.annotation.RestMethod; import org.mariotaku.restfu.http.Authorization; import org.mariotaku.restfu.http.Endpoint; +import org.mariotaku.restfu.http.FileValue; import org.mariotaku.restfu.http.RestHttpClient; +import org.mariotaku.restfu.http.RestHttpRequest; +import org.mariotaku.restfu.http.RestHttpResponse; +import org.mariotaku.restfu.http.mime.StringTypedData; +import org.mariotaku.restfu.http.mime.TypedData; import org.mariotaku.twidere.TwidereConstants; import org.mariotaku.twidere.api.twitter.Twitter; +import org.mariotaku.twidere.api.twitter.TwitterException; +import org.mariotaku.twidere.api.twitter.TwitterOAuth; +import org.mariotaku.twidere.api.twitter.TwitterUpload; +import org.mariotaku.twidere.api.twitter.TwitterUserStream; +import org.mariotaku.twidere.api.twitter.auth.BasicAuthorization; +import org.mariotaku.twidere.api.twitter.auth.EmptyAuthorization; import org.mariotaku.twidere.api.twitter.auth.OAuthAuthorization; +import org.mariotaku.twidere.api.twitter.auth.OAuthEndpoint; +import org.mariotaku.twidere.api.twitter.auth.OAuthToken; import org.mariotaku.twidere.api.twitter.util.TwitterConverter; import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.model.ConsumerKeyType; @@ -24,7 +48,13 @@ import org.mariotaku.twidere.util.net.OkHttpRestClient; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.SocketAddress; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static android.text.TextUtils.isEmpty; @@ -109,29 +139,237 @@ public class TwitterAPIFactory implements TwidereConstants { final String consumerSecret = ((OAuthAuthorization) auth).getConsumerSecret(); final ConsumerKeyType officialKeyType = TwitterContentUtils.getOfficialKeyType(context, consumerKey, consumerSecret); if (officialKeyType != ConsumerKeyType.UNKNOWN) { - userAgent = TwitterAPIUtils.getUserAgentName(officialKeyType); + userAgent = getUserAgentName(officialKeyType); } else { - userAgent = TwitterAPIUtils.getTwidereUserAgent(context); + userAgent = getTwidereUserAgent(context); } } else { - userAgent = TwitterAPIUtils.getTwidereUserAgent(context); + userAgent = getTwidereUserAgent(context); } factory.setClient(getDefaultHttpClient(context)); factory.setConverter(new TwitterConverter()); factory.setEndpoint(endpoint); factory.setAuthorization(auth); - factory.setRequestInfoFactory(new TwitterAPIUtils.TwidereRequestInfoFactory()); - factory.setHttpRequestFactory(new TwitterAPIUtils.TwidereHttpRequestFactory(userAgent)); - factory.setExceptionFactory(new TwitterAPIUtils.TwidereExceptionFactory()); + factory.setRequestInfoFactory(new TwidereRequestInfoFactory()); + factory.setHttpRequestFactory(new TwidereHttpRequestFactory(userAgent)); + factory.setExceptionFactory(new TwidereExceptionFactory()); return factory.build(cls); } public static T getInstance(final Context context, final Endpoint endpoint, final ParcelableCredentials credentials, Class cls) { - return TwitterAPIFactory.getInstance(context, endpoint, TwitterAPIUtils.getAuthorization(credentials), cls); + return TwitterAPIFactory.getInstance(context, endpoint, getAuthorization(credentials), cls); } static T getInstance(final Context context, final ParcelableCredentials credentials, final Class cls) { if (credentials == null) return null; - return TwitterAPIFactory.getInstance(context, TwitterAPIUtils.getEndpoint(credentials, cls), credentials, cls); + return TwitterAPIFactory.getInstance(context, getEndpoint(credentials, cls), credentials, cls); + } + + public static Endpoint getEndpoint(ParcelableCredentials credentials, Class cls) { + final String apiUrlFormat; + final boolean sameOAuthSigningUrl = credentials.same_oauth_signing_url; + final boolean noVersionSuffix = credentials.no_version_suffix; + if (!isEmpty(credentials.api_url_format)) { + apiUrlFormat = credentials.api_url_format; + } else { + apiUrlFormat = DEFAULT_TWITTER_API_URL_FORMAT; + } + final String domain, versionSuffix; + if (Twitter.class.isAssignableFrom(cls)) { + domain = "api"; + versionSuffix = noVersionSuffix ? null : "/1.1/"; + } else if (TwitterUpload.class.isAssignableFrom(cls)) { + domain = "upload"; + versionSuffix = noVersionSuffix ? null : "/1.1/"; + } else if (TwitterOAuth.class.isAssignableFrom(cls)) { + domain = "api"; + versionSuffix = "oauth"; + } else if (TwitterUserStream.class.isAssignableFrom(cls)) { + domain = "userstream"; + versionSuffix = noVersionSuffix ? null : "/1.1/"; + } else { + throw new TwitterConverter.UnsupportedTypeException(cls); + } + final String endpointUrl; + endpointUrl = getApiUrl(apiUrlFormat, domain, versionSuffix); + if (credentials.auth_type == ParcelableCredentials.AUTH_TYPE_XAUTH || credentials.auth_type == ParcelableCredentials.AUTH_TYPE_OAUTH) { + final String signEndpointUrl; + if (!sameOAuthSigningUrl) { + signEndpointUrl = getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, domain, versionSuffix); + } else { + signEndpointUrl = endpointUrl; + } + return new OAuthEndpoint(endpointUrl, signEndpointUrl); + } + return new Endpoint(endpointUrl); + } + + public static Authorization getAuthorization(ParcelableCredentials credentials) { + switch (credentials.auth_type) { + case ParcelableCredentials.AUTH_TYPE_OAUTH: + case ParcelableCredentials.AUTH_TYPE_XAUTH: { + final String consumerKey = TextUtils.isEmpty(credentials.consumer_key) ? + TWITTER_CONSUMER_KEY_LEGACY : credentials.consumer_key; + final String consumerSecret = TextUtils.isEmpty(credentials.consumer_secret) ? + TWITTER_CONSUMER_SECRET_LEGACY : credentials.consumer_secret; + final OAuthToken accessToken = new OAuthToken(credentials.oauth_token, credentials.oauth_token_secret); + return new OAuthAuthorization(consumerKey, consumerSecret, accessToken); + } + case ParcelableCredentials.AUTH_TYPE_BASIC: { + final String screenName = credentials.screen_name; + final String username = credentials.basic_auth_username; + final String loginName = username != null ? username : screenName; + final String password = credentials.basic_auth_password; + if (isEmpty(loginName) || isEmpty(password)) return null; + return new BasicAuthorization(loginName, password); + } + } + return new EmptyAuthorization(); + } + + private static void addParameter(List> params, String name, Object value) { + params.add(Pair.create(name, String.valueOf(value))); + } + + private static void addPart(List> params, String name, Object value) { + final TypedData typedData = new StringTypedData(String.valueOf(value), Charset.defaultCharset()); + params.add(Pair.create(name, typedData)); + } + + public static String getApiBaseUrl(String format, final String domain) { + if (format == null) return null; + final Matcher matcher = Pattern.compile("\\[(\\.?)DOMAIN(\\.?)\\]").matcher(format); + if (!matcher.find()) { + // For backward compatibility + format = substituteLegacyApiBaseUrl(format, domain); + if (!format.endsWith("/1.1") && !format.endsWith("/1.1/")) { + return format; + } + final String versionSuffix = "/1.1"; + final int suffixLength = versionSuffix.length(); + final int lastIndex = format.lastIndexOf(versionSuffix); + return format.substring(0, lastIndex) + format.substring(lastIndex + suffixLength); + } + if (TextUtils.isEmpty(domain)) return matcher.replaceAll(""); + return matcher.replaceAll(String.format("$1%s$2", domain)); + } + + private static String substituteLegacyApiBaseUrl(@NonNull String format, String domain) { + final int startOfHost = format.indexOf("://") + 3, endOfHost = format.indexOf('/', startOfHost); + final String host = endOfHost != -1 ? format.substring(startOfHost, endOfHost) : format.substring(startOfHost); + if (!host.equalsIgnoreCase("api.twitter.com")) return format; + return format.substring(0, startOfHost) + domain + ".twitter.com" + format.substring(endOfHost); + } + + public static String getApiUrl(final String pattern, final String domain, final String appendPath) { + final String urlBase = getApiBaseUrl(pattern, domain); + if (urlBase == null) return null; + if (appendPath == null) return urlBase.endsWith("/") ? urlBase : urlBase + "/"; + final StringBuilder sb = new StringBuilder(urlBase); + if (urlBase.endsWith("/")) { + sb.append(appendPath.startsWith("/") ? appendPath.substring(1) : appendPath); + } else { + if (appendPath.startsWith("/")) { + sb.append(appendPath); + } else { + sb.append('/'); + sb.append(appendPath); + } + } + return sb.toString(); + } + + public static String getUserAgentName(ConsumerKeyType type) { + switch (type) { + case TWITTER_FOR_ANDROID: { + return "TwitterAndroid"; + } + case TWITTER_FOR_IPHONE: { + return "Twitter-iPhone"; + } + case TWITTER_FOR_IPAD: { + return "Twitter-iPad"; + } + case TWITTER_FOR_MAC: { + return "Twitter-Mac"; + } + } + return "Twitter"; + } + + public static String getTwidereUserAgent(final Context context) { + final PackageManager pm = context.getPackageManager(); + try { + final PackageInfo pi = pm.getPackageInfo(TWIDERE_PACKAGE_NAME, 0); + return TWIDERE_APP_NAME + " " + TWIDERE_PROJECT_URL + " / " + pi.versionName; + } catch (final PackageManager.NameNotFoundException e) { + return TWIDERE_APP_NAME + " " + TWIDERE_PROJECT_URL; + } + } + + public static class TwidereRequestInfoFactory implements RequestInfoFactory { + @Override + public RestRequestInfo create(RestMethodInfo methodInfo) { + final RestMethod method = methodInfo.getMethod(); + final String path = methodInfo.getPath(); + final List> queries = new ArrayList<>(methodInfo.getQueries()); + final List> forms = new ArrayList<>(methodInfo.getForms()); + final List> headers = methodInfo.getHeaders(); + final List> parts = methodInfo.getParts(); + final FileValue file = methodInfo.getFile(); + final Map extras = methodInfo.getExtras(); + if (parts.isEmpty()) { + final List> params = method.hasBody() ? forms : queries; + addParameter(params, "include_cards", true); + addParameter(params, "cards_platform", "Android-12"); + addParameter(params, "include_entities", true); + addParameter(params, "include_my_retweet", 1); + addParameter(params, "include_rts", 1); + addParameter(params, "include_reply_count", true); + addParameter(params, "include_descendent_reply_count", true); + } else { + addPart(parts, "include_cards", true); + addPart(parts, "cards_platform", "Android-12"); + addPart(parts, "include_entities", true); + addPart(parts, "include_my_retweet", 1); + addPart(parts, "include_rts", 1); + addPart(parts, "include_reply_count", true); + addPart(parts, "include_descendent_reply_count", true); + } + return new RestRequestInfo(method.value(), path, queries, forms, headers, parts, file, + methodInfo.getBody(), extras); + } + } + + public static class TwidereHttpRequestFactory implements HttpRequestFactory { + + private final String userAgent; + + public TwidereHttpRequestFactory(final String userAgent) { + this.userAgent = userAgent; + } + + @Override + public RestHttpRequest create(@NonNull Endpoint endpoint, @NonNull RestRequestInfo info, + @Nullable Authorization authorization) { + final String restMethod = info.getMethod(); + final String url = Endpoint.constructUrl(endpoint.getUrl(), info); + final ArrayList> headers = new ArrayList<>(info.getHeaders()); + + if (authorization != null && authorization.hasAuthorization()) { + headers.add(Pair.create("Authorization", authorization.getHeader(endpoint, info))); + } + headers.add(Pair.create("User-Agent", userAgent)); + return new RestHttpRequest(restMethod, url, headers, info.getBody(), null); + } + } + + public static class TwidereExceptionFactory implements ExceptionFactory { + @Override + public Exception newException(Throwable cause, RestHttpRequest request, RestHttpResponse response) { + final TwitterException te = new TwitterException(cause); + te.setResponse(response); + return te; + } } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java index 2ab1bbe5e..7c9ce3867 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java @@ -252,7 +252,6 @@ import java.util.zip.CRC32; import javax.net.ssl.SSLException; import edu.tsinghua.spice.SpiceService; -import edu.ucdavis.earlybird.UCDService; import static android.text.TextUtils.isEmpty; import static android.text.format.DateUtils.getRelativeTimeSpanString; @@ -3418,15 +3417,12 @@ public final class Utils implements Constants { public static void startUsageStatisticsServiceIfNeeded(final Context context) { final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); - final Intent profilingServiceIntent = new Intent(context, UCDService.class); //spice final Intent spiceProfilingServiceIntent = new Intent(context, SpiceService.class); if (prefs.getBoolean(KEY_USAGE_STATISTICS, false)) { - context.startService(profilingServiceIntent); //spice context.startService(spiceProfilingServiceIntent); } else { - context.stopService(profilingServiceIntent); //spice context.stopService(spiceProfilingServiceIntent); } diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/imageloader/TwidereImageDownloader.java b/twidere/src/main/java/org/mariotaku/twidere/util/imageloader/TwidereImageDownloader.java index b425e33a6..2a3216eda 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/imageloader/TwidereImageDownloader.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/imageloader/TwidereImageDownloader.java @@ -51,7 +51,6 @@ import org.mariotaku.twidere.model.ParcelableMedia; import org.mariotaku.twidere.util.MediaPreviewUtils; import org.mariotaku.twidere.util.SharedPreferencesWrapper; import org.mariotaku.twidere.util.TwidereLinkify; -import org.mariotaku.twidere.util.TwitterAPIUtils; import org.mariotaku.twidere.util.TwitterAPIFactory; import org.mariotaku.twidere.util.Utils; @@ -129,7 +128,7 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const final String host = uri.getHost(); final String domain = host.substring(0, host.lastIndexOf(".twitter.com")); final String path = uri.getPath(); - sb.append(TwitterAPIUtils.getApiUrl(apiUrlFormat, domain, path)); + sb.append(TwitterAPIFactory.getApiUrl(apiUrlFormat, domain, path)); final String query = uri.getQuery(); if (!TextUtils.isEmpty(query)) { sb.append("?"); @@ -152,7 +151,7 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const if (isTwitterAuthRequired(uri) && extras instanceof AccountExtra) { final AccountExtra accountExtra = (AccountExtra) extras; account = ParcelableAccount.getCredentials(mContext, accountExtra.account_id); - auth = TwitterAPIUtils.getAuthorization(account); + auth = TwitterAPIFactory.getAuthorization(account); } else { account = null; auth = null; diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpRestClient.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpRestClient.java index 96b18024a..cb516dfef 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpRestClient.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpRestClient.java @@ -38,6 +38,7 @@ import org.mariotaku.restfu.http.RestHttpClient; import org.mariotaku.restfu.http.RestHttpRequest; import org.mariotaku.restfu.http.RestHttpResponse; import org.mariotaku.restfu.http.mime.TypedData; +import org.mariotaku.twidere.util.DebugModeUtils; import java.io.IOException; import java.io.InputStream; @@ -60,6 +61,7 @@ public class OkHttpRestClient implements RestHttpClient { public OkHttpRestClient(OkHttpClient client) { this.client = client; + DebugModeUtils.initForHttpClient(client); } @NonNull diff --git a/twidere/src/main/res-localized/layout/action_item_space.xml b/twidere/src/main/res-localized/layout/action_item_space.xml new file mode 100644 index 000000000..9066c7adf --- /dev/null +++ b/twidere/src/main/res-localized/layout/action_item_space.xml @@ -0,0 +1,24 @@ + + + + diff --git a/twidere/src/main/res-svg2png/drawable-hdpi/ic_stat_refresh.png b/twidere/src/main/res-svg2png/drawable-hdpi/ic_stat_refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..88ba055526276f152fcace8326e8ce605543fccd GIT binary patch literal 718 zcmV;<0x|uGP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00004XF*Lt006O$eEU(800001 zb5ch_0Itp)=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02rG902rGANp*vi0006d zNklI$uP`2R)9!IkXEkH9+WjyP;tp&~7w*3`m?xaB^ z?L#*LJgYoaQBbh}0Y-V`3Yrf1i1JK1mL&tsHkxDC3pAls=qnljaKWhMYJ~+#27p;Y zbHXmQp_?%FS!0*h{oYIiGe$78&>eyc?V%Fu-@{nLH#&Uw495DDuPpL-$pomt`c;7pe!=?l zCO|y%z6by{S%1m|D8pRd6#)8V{gi2xNlHIRx=93?08x<<0OE6WO@Q85e^LNwIx5gJ z>#qp_t?)Er0(8y#=_m($j4z;>p`X9dT4*3d);pRA?!&sh(u5`GM zb4kP@mu2o9+gc`eC-O=M?Qsp97m=n9%L!0RaE3I*qLK><%77x9435?>yPc)+w&eA0xR z?F(KW&2D76vNYUd!vn1;(-wxgIkVdrs7mFC?QuMnaD=H;<8O-u_cw=^8A3W84wt*H zH_g28W&flZlSDMqn3f1N{NUf#a*WGqy(z3g;TT8fBh#>8cw~%CImqVDB*ADA~8&L^UAEuEFg^NY2i=a}=0FZ?j&o uNK#R47MOZ*!PE0BRUtqAHm?(9VmRwsEdP^d<3eDlGkCiCxvX004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00004XF*Lt006O$eEU(800001 zb5ch_0Itp)=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02rG902rGANp*vi00084 zNkl0i8e_A^pbJ z7hKofNn8L(x1w1Brh(Rwug4aVia|U@#20{;h{L24nE{YDq45{!jk6Zu{YC2nK)wsj z3DEBIaRtZ|{sCp+UWfb>)%71t*hud-L_SC7 zNmgVR!l2D){xboyAoWZ56z``EqJCrOcyES-%)kI6Uz8?KRsgDXeY08gNrcb@>+fk~ zc(f7hv&VxH0=iiLNHJ4AX8nwW0KV@(CNXJJKjZX0km!AS#nkgk(>qjp2<9y+2dWwY;=ugAxdT$By@hW1Jk4xn_>dUT@q-*4uc%Do<8GBl1*|8nPpl zp8F+f=Fl1f`Er=wb!~dSfnC$(KsoG-Zo=fBfFHmL$Umvx3pKEGMB;ylc&zkXDulM3 z*Gt~FtVA(>M004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00004XF*Lt006O$eEU(800001 zb5ch_0Itp)=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02rG902rGANp*vi000Bs zNkl*VuTJI96C5SC^}?lp+g1-hd_J}UzU*f^XI?&@4ZX&;BoXW|NVF0 zfA{XayK4}PWF#XwOw#FeZfj~!Mj@kRO^`B52a*~{8O5_r1tiUYR6x=WNF0(6fJ7nr z0!R#!Pk=-qg+k6?7Lrq-lc4z?Eyk!~Aq>Nnp#lU@a*#}e&XA59R_O#%=m5+ZB=ew) z7N9tXludaWT?MU!7E*dm(aRA8aL|^#1}&#)uwnF6y#oYrCLno72G?si)&T(=oKjCg z$71~a59mkG51@OX`;`9D0>`Qi0yx(pc^>1Z2xJX(3p)C@Pd#ejSOWx|D$~e`l3ma$ zbg-d)T3H1Ia0+CQxw_i8#6#yE`e1Xc0-~in${?eixeT4#@)3@WSPUJ&5>wU!Js}AP zKHxFXX%Rs1;&JkhxoL$X=er~vNIv6&K;FFb5rk3o5vJ@8bncS^IC=8oZ#o4;o^p*T zZWzW#HsN%oM)uO#2)Y#E4Bj>JT+QI*`oIb3?^&0C=9v5!(7~@#D-OIHSIyr{@iixa z=qpv2;?+Q2mYDphB*r?)2%2U5rzU*CZ3TedlmFE#2JO%PUICz6O#UXcz3pNIp{z6cGs4rW5@CNfT{?=-`Z!}~0M8qC z(De4$6DGe!+aPWLQCP9w1Lw5KDF(q=HhBJCM6_O~-A1RO#(f$^8sMN|u1EN7iFY~^ z0|FpusA~$~;L7%DFGchL zr~btxOS?EA6F78(?NPw*jica{x&UyDH}SH*z=7u`$q~I0hC)747S1{G7N6IZDR zpeq2Tm1g5zO)(527YwVx5z+|$pWwc-v4m?g(t|*1lF{udf_a-X;Pe7eTu1;x004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00004XF*Lt006O$eEU(800001 zb5ch_0Itp)=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02rG902rGANp*vi000Ft zNklk!a^{@6%i~fEK&sG_sC13kej)?nceqh_k+ggpdSKDMDxhs1qSX z0aS?)ssL(42w4CXB7`o0coFg-fM^l&B7j&CV(F}bv}PRk!CGM@Sj&G_s_~MS;yAuv z2vD8$tvGbUdSC}(TO8j)j0mwH(i0rcGwGeM#Pcmhh!6`QzYm8&*p8HMow*1}#>7)i zABFA7=n+b}YylviI@Bkyt}LS>)c(u469DA5m6b_Fwc70;VPfY-h zaPGpc)_I9l*gR|zR)Hhn_*fMfh|%hSo19|KVzL+)@>69DAX z0B6eb`k!FEAgYo#@_n{|Da$y28g>pu{mCQwUIakxKa4}W#i^4Z>7BFRf1TYQ0DvAa8(qOnMLV%x&1^Cfm>lY!wvSI;D&%Q;10Ii13OtTB}j;4Zw zsxU=wNg;q=n0$Oif&eQPBW11F?z?|;AwZ?US|k}Q8U$D}lkE2 zR=!jO_-rWe(#Sj~3U+Gfgcl6uyLqRaHgrekS>A=r1;9Y-tA#J@Qz(FG!DY_HB9p6e zz#Bt(zv~T6DY&15hSSO}?&V5=X+wEQSu3~^RiEdf5%R1g0X|r`p^}o?PtR$}X_$AF zJmN$EUh%4y3qV^^ZhIih$HzBrMeECr-rbMO7C?Bo$+W~+Mw_SVxn>6rrwyll<9C%M z0B_|OS4=*QdS@(79dx~T{ zJNbysM|^BU@l^Ahnf&7xr@zB{&5IX65&13bc5KqAsAZq=5%!87oq8gl+|BFAE|HKb zRIjhK?Icg+bFHUQ?m!Li-VgE@eZ6Cn2lCn1UxQtOZLQ&_!yx~e&-YA1C7&n%_DAbm z=X;{szfVM?-Rr*JH3@-y9z+qrw1`fBcQEPoZk(czg}FQt9sIOpWk%;r@P|0=8Zm(U59GIBSAu!*d*cci$WQI64l zgAy)i`E*1|)~2LR*oO$K?B6L%lRo_SO|MNpF^8L9}X z(o{nfL0z73Xd. --> - + android:divider="?dividerVertical" + android:orientation="vertical" + android:showDividers="middle"> + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/layout/list_item_dashboard_menu.xml b/twidere/src/main/res/layout/list_item_dashboard_menu.xml new file mode 100644 index 000000000..1d94cad89 --- /dev/null +++ b/twidere/src/main/res/layout/list_item_dashboard_menu.xml @@ -0,0 +1,52 @@ + + + + + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/layout/list_item_menu.xml b/twidere/src/main/res/layout/list_item_menu.xml index d07a7bb60..e231dc745 100644 --- a/twidere/src/main/res/layout/list_item_menu.xml +++ b/twidere/src/main/res/layout/list_item_menu.xml @@ -22,7 +22,7 @@ android:layout_height="wrap_content" android:descendantFocusability="blocksDescendants" android:gravity="center_vertical" - android:minHeight="48dp" + android:minHeight="?listPreferredItemHeightSmall" android:orientation="horizontal"> + + + + + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/values/strings.xml b/twidere/src/main/res/values/strings.xml index d67d75a66..475f15117 100644 --- a/twidere/src/main/res/values/strings.xml +++ b/twidere/src/main/res/values/strings.xml @@ -44,6 +44,7 @@ Password Twidere database provider Refresh service + Streaming service Background operation service Open in browser Tap to load more @@ -754,4 +755,8 @@ Play Pause Jump to top + Timeline streaming running + Streaming + Enable streaming + Dark theme \ No newline at end of file diff --git a/twidere/src/main/res/xml/preferences_account_refresh.xml b/twidere/src/main/res/xml/preferences_account_refresh.xml index 0dc42c8dc..820014226 100644 --- a/twidere/src/main/res/xml/preferences_account_refresh.xml +++ b/twidere/src/main/res/xml/preferences_account_refresh.xml @@ -3,7 +3,13 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/auto_refresh"> + + + + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/xml/preferences_notifications.xml b/twidere/src/main/res/xml/preferences_notifications.xml index fcc35ff46..dcb6da7ba 100644 --- a/twidere/src/main/res/xml/preferences_notifications.xml +++ b/twidere/src/main/res/xml/preferences_notifications.xml @@ -18,12 +18,6 @@ android:summary="@string/silent_notifications_summary" android:title="@string/silent_notifications"/> - - - @@ -7,20 +8,18 @@ android:key="cat_theme_preview" android:order="11" android:title="@string/preview"> - + - + android:key="theme" + android:title="@string/dark_theme"> - + android:value="true"/> + + android:value="true"/> + android:value="true"/> diff --git a/twidere/src/main/svg-png/ic_stat_refresh-mdpi.svg b/twidere/src/main/svg-png/ic_stat_refresh-mdpi.svg new file mode 100644 index 000000000..84c386e68 --- /dev/null +++ b/twidere/src/main/svg-png/ic_stat_refresh-mdpi.svg @@ -0,0 +1,4 @@ + + + + diff --git a/twidere.extension.streaming/src/androidTest/java/org/mariotaku/twidere/extension/streaming/ApplicationTest.java b/twidere/src/release/java/org/mariotaku/twidere/util/DebugModeUtils.java similarity index 66% rename from twidere.extension.streaming/src/androidTest/java/org/mariotaku/twidere/extension/streaming/ApplicationTest.java rename to twidere/src/release/java/org/mariotaku/twidere/util/DebugModeUtils.java index 6f3b2f23d..a03bf90cf 100644 --- a/twidere.extension.streaming/src/androidTest/java/org/mariotaku/twidere/extension/streaming/ApplicationTest.java +++ b/twidere/src/release/java/org/mariotaku/twidere/util/DebugModeUtils.java @@ -1,5 +1,5 @@ /* - * Twidere - Twitter client for Android + * Twidere - Twitter client for Android * * Copyright (C) 2012-2015 Mariotaku Lee * @@ -17,16 +17,24 @@ * along with this program. If not, see . */ -package org.mariotaku.twidere.extension.streaming; +package org.mariotaku.twidere.util; import android.app.Application; -import android.test.ApplicationTestCase; + +import com.squareup.okhttp.OkHttpClient; /** - * Testing Fundamentals + * Created by mariotaku on 15/5/27. */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); +public class DebugModeUtils { + + public static void initForHttpClient(final OkHttpClient client) { + // No-op } -} \ No newline at end of file + + + public static void initForApplication(final Application application) { + // No-op + } + +}