diff --git a/global.gradle b/global.gradle
index feeba163e..c0d49cddd 100644
--- a/global.gradle
+++ b/global.gradle
@@ -17,8 +17,8 @@
* along with this program. If not, see .
*/
android {
- compileSdkVersion 22
- buildToolsVersion '22.0.1'
+ compileSdkVersion 23
+ buildToolsVersion '23.0.0'
lintOptions {
abortOnError false
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 6bf3aaa53..50c99ee33 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Aug 16 21:56:31 CST 2015
+#Wed Aug 19 14:17:02 CST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-all.zip
diff --git a/settings.gradle b/settings.gradle
index 86486550c..b79867b3e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -5,7 +5,7 @@ include ':twidere.wear'
include ':twidere.donate.nyanwp'
include ':twidere.donate.nyanwp.wear'
include ':twidere.component.nyan'
-include ':twidere.extension.twitlonger'
+//include ':twidere.extension.twitlonger'
include ':twidere.extension.push.xiaomi'
include ':twidere.extension.launcher.compose'
include ':twidere.extension.shortener.gist'
\ No newline at end of file
diff --git a/twidere/build.gradle b/twidere/build.gradle
index e0778da6a..681c390fa 100644
--- a/twidere/build.gradle
+++ b/twidere/build.gradle
@@ -13,7 +13,7 @@ android {
defaultConfig {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
- targetSdkVersion 22
+ targetSdkVersion 23
versionCode 117
versionName "0.3.0"
multiDexEnabled true
@@ -59,10 +59,10 @@ dependencies {
apt 'com.bluelinelabs:logansquare-compiler:1.1.0'
apt 'com.hannesdorfmann.parcelableplease:processor:1.0.1'
compile 'com.android.support:multidex:1.0.1'
- compile 'com.android.support:support-v13:22.2.1'
- compile 'com.android.support:appcompat-v7:22.2.1'
- compile 'com.android.support:cardview-v7:22.2.1'
- compile 'com.android.support:recyclerview-v7:22.2.1'
+ compile 'com.android.support:support-v13:23.0.0'
+ compile 'com.android.support:appcompat-v7:23.0.0'
+ compile 'com.android.support:cardview-v7:23.0.0'
+ compile 'com.android.support:recyclerview-v7:23.0.0'
compile 'com.twitter:twitter-text:1.12.1'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'
compile 'com.squareup:otto:1.3.8'
@@ -91,7 +91,7 @@ dependencies {
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
compile 'com.github.mariotaku:PickNCrop:44b09cbc69'
compile 'com.diogobernardino:williamchart:2.0.1'
- googleCompile 'com.google.android.gms:play-services-maps:7.5.0'
+ googleCompile 'com.google.android.gms:play-services-maps:7.8.0'
googleCompile 'com.google.maps.android:android-maps-utils:0.4'
fdroidCompile 'org.osmdroid:osmdroid-android:4.3'
fdroidCompile 'org.slf4j:slf4j-simple:1.7.12'
diff --git a/twidere/src/fdroid/res/layout/activity_osm_viewer.xml b/twidere/src/fdroid/res/layout/activity_osm_viewer.xml
index 4bb321054..19dc60d0f 100644
--- a/twidere/src/fdroid/res/layout/activity_osm_viewer.xml
+++ b/twidere/src/fdroid/res/layout/activity_osm_viewer.xml
@@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
- *
- * 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 edu.tsinghua.hotmobi.model;
-
-import com.bluelinelabs.logansquare.annotation.JsonField;
-import com.bluelinelabs.logansquare.annotation.JsonObject;
-
-import java.util.Map;
-
-/**
- * Created by mariotaku on 15/8/8.
- */
-@JsonObject
-public class FirstLaunchEvent extends BaseEvent{
- @JsonField(name = "device_id")
- String deviceId;
- @JsonField(name = "configuration")
- Map configuration;
-
-}
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/MediaEvent.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/MediaEvent.java
index b280d1330..966df47dd 100644
--- a/twidere/src/main/java/edu/tsinghua/hotmobi/model/MediaEvent.java
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/MediaEvent.java
@@ -27,8 +27,6 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
-import edu.tsinghua.hotmobi.HotMobiLogger;
-
/**
* Created by mariotaku on 15/8/7.
*/
@@ -39,12 +37,10 @@ public class MediaEvent extends BaseEvent {
long id;
@JsonField(name = "user_id")
long userId;
- @JsonField(name = "tweet_type")
- int tweetType;
- @JsonField(name = "timeline_type")
- int timelineType;
- @JsonField(name = "action")
- int action;
+ @JsonField(name = "tweet_type", typeConverter = TweetType.TweetTypeConverter.class)
+ TweetType tweetType;
+ @JsonField(name = "timeline_type", typeConverter = TimelineType.TimelineTypeConverter.class)
+ TimelineType timelineType;
@JsonField(name = "preview_url")
String previewUrl;
@JsonField(name = "media_url")
@@ -52,7 +48,7 @@ public class MediaEvent extends BaseEvent {
@JsonField(name = "preview_enabled")
boolean previewEnabled;
- public static MediaEvent create(Context context, ParcelableStatus status, ParcelableMedia media, int timelineType, boolean previewEnabled) {
+ public static MediaEvent create(Context context, ParcelableStatus status, ParcelableMedia media, TimelineType timelineType, boolean previewEnabled) {
final MediaEvent event = new MediaEvent();
event.markStart(context);
event.setId(status.id);
@@ -61,7 +57,7 @@ public class MediaEvent extends BaseEvent {
event.setPreviewUrl(media.preview_url);
event.setPreviewEnabled(previewEnabled);
event.setTimelineType(timelineType);
- event.setTweetType(HotMobiLogger.getTweetType(status));
+ event.setTweetType(TweetType.getTweetType(status));
return event;
}
@@ -77,10 +73,6 @@ public class MediaEvent extends BaseEvent {
this.previewUrl = previewUrl;
}
- public void setAction(int action) {
- this.action = action;
- }
-
public void setId(long id) {
this.id = id;
}
@@ -89,20 +81,13 @@ public class MediaEvent extends BaseEvent {
this.userId = userId;
}
- public void setTweetType(int tweetType) {
+ public void setTweetType(TweetType tweetType) {
this.tweetType = tweetType;
}
- public void setTimelineType(int timelineType) {
+ public void setTimelineType(TimelineType timelineType) {
this.timelineType = timelineType;
}
- public interface Action {
- int OPEN = 0;
- int RETWEET = 1;
- int FAVORITE = 2;
-
- int UNFAVORITE = -2;
- }
}
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/RefreshEvent.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/RefreshEvent.java
index 398a9a0b9..854b9b4c4 100644
--- a/twidere/src/main/java/edu/tsinghua/hotmobi/model/RefreshEvent.java
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/RefreshEvent.java
@@ -32,18 +32,18 @@ public class RefreshEvent extends BaseEvent {
@JsonField(name = "ids")
long[] ids;
- @JsonField(name = "timeline_type")
- int timelineType;
+ @JsonField(name = "timeline_type", typeConverter = TimelineType.TimelineTypeConverter.class)
+ TimelineType timelineType;
public void setIds(long[] ids) {
this.ids = ids;
}
- public void setTimelineType(int timelineType) {
+ public void setTimelineType(TimelineType timelineType) {
this.timelineType = timelineType;
}
- public static RefreshEvent create(final Context context, long[] ids, int timelineType) {
+ public static RefreshEvent create(final Context context, long[] ids, TimelineType timelineType) {
final RefreshEvent event = new RefreshEvent();
event.markStart(context);
event.setIds(ids);
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/ScrollRecord.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/ScrollRecord.java
index c1c522c54..b32f23f17 100644
--- a/twidere/src/main/java/edu/tsinghua/hotmobi/model/ScrollRecord.java
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/ScrollRecord.java
@@ -27,8 +27,30 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
*/
@JsonObject
public class ScrollRecord {
- @JsonField(name = "count")
- long count;
- @JsonField(name = "total")
- long total;
+ @JsonField(name = "id")
+ long id;
+ @JsonField(name = "timestamp")
+ long timestamp;
+ @JsonField(name = "scroll_state")
+ int scrollState;
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public void setScrollState(int scrollState) {
+ this.scrollState = scrollState;
+ }
+
+ public static ScrollRecord create(long id, long timestamp, int scrollState) {
+ final ScrollRecord record = new ScrollRecord();
+ record.setId(id);
+ record.setTimestamp(timestamp);
+ record.setScrollState(scrollState);
+ return record;
+ }
}
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/SessionEvent.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/SessionEvent.java
index e250f2b56..83d5e5a3f 100644
--- a/twidere/src/main/java/edu/tsinghua/hotmobi/model/SessionEvent.java
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/SessionEvent.java
@@ -19,14 +19,32 @@
package edu.tsinghua.hotmobi.model;
-import java.util.Map;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
/**
* Created by mariotaku on 15/8/8.
*/
+@JsonObject
public class SessionEvent extends BaseEvent {
- Map scrollRecords;
+ @JsonField(name = "configuration")
+ String configuration;
+ public static SessionEvent create(Context context) {
+ final SessionEvent event = new SessionEvent();
+ event.markStart(context);
+ final Context appContext = context.getApplicationContext();
+ final Configuration conf = appContext.getResources().getConfiguration();
+ event.setConfiguration(conf.toString());
+ return event;
+ }
+
+ public void setConfiguration(String configuration) {
+ this.configuration = configuration;
+ }
}
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/TimelineType.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/TimelineType.java
new file mode 100644
index 000000000..a3a6bf4d2
--- /dev/null
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/TimelineType.java
@@ -0,0 +1,58 @@
+/*
+ * 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 edu.tsinghua.hotmobi.model;
+
+import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter;
+
+/**
+ * Created by mariotaku on 15/8/18.
+ */
+public enum TimelineType {
+ HOME("home"), INTERACTIONS("interactions"), OTHER("other");
+
+ private final String value;
+
+ TimelineType(String value) {
+ this.value = value;
+ }
+
+ public static TimelineType parse(String type) {
+ if (HOME.value.equalsIgnoreCase(type)) {
+ return HOME;
+ } else if (INTERACTIONS.value.equalsIgnoreCase(type)) {
+ return INTERACTIONS;
+ }
+ return OTHER;
+ }
+
+ public static class TimelineTypeConverter extends StringBasedTypeConverter {
+
+ @Override
+ public TimelineType getFromString(String string) {
+ return TimelineType.parse(string);
+ }
+
+ @Override
+ public String convertToString(TimelineType timelineType) {
+ if (timelineType == null) return null;
+ return timelineType.value;
+ }
+ }
+}
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetEvent.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetEvent.java
index 42b2323fe..df70c2517 100644
--- a/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetEvent.java
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetEvent.java
@@ -23,11 +23,10 @@ import android.content.Context;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
+import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter;
import org.mariotaku.twidere.model.ParcelableStatus;
-import edu.tsinghua.hotmobi.HotMobiLogger;
-
/**
* Created by mariotaku on 15/8/7.
*/
@@ -36,16 +35,33 @@ public class TweetEvent extends BaseEvent {
@JsonField(name = "id")
long id;
+ @JsonField(name = "account_id")
+ long accountId;
@JsonField(name = "user_id")
long userId;
- @JsonField(name = "tweet_type")
- int tweetType;
- @JsonField(name = "timeline_type")
- int timelineType;
- @JsonField(name = "action")
- int action;
+ @JsonField(name = "tweet_type", typeConverter = TweetType.TweetTypeConverter.class)
+ TweetType tweetType;
+ @JsonField(name = "timeline_type", typeConverter = TimelineType.TimelineTypeConverter.class)
+ TimelineType timelineType;
+ @JsonField(name = "action", typeConverter = Action.TweetActionConverter.class)
+ Action action;
- public void setAction(int action) {
+ public static TweetEvent create(Context context, ParcelableStatus status, TimelineType timelineType) {
+ final TweetEvent event = new TweetEvent();
+ event.markStart(context);
+ event.setId(status.id);
+ event.setAccountId(status.account_id);
+ event.setUserId(status.user_id);
+ event.setTimelineType(timelineType);
+ event.setTweetType(TweetType.getTweetType(status));
+ return event;
+ }
+
+ public void setAccountId(long accountId) {
+ this.accountId = accountId;
+ }
+
+ public void setAction(Action action) {
this.action = action;
}
@@ -57,30 +73,54 @@ public class TweetEvent extends BaseEvent {
this.userId = userId;
}
- public void setTweetType(int tweetType) {
+ public void setTweetType(TweetType tweetType) {
this.tweetType = tweetType;
}
- public void setTimelineType(int timelineType) {
+ public void setTimelineType(TimelineType timelineType) {
this.timelineType = timelineType;
}
- public static TweetEvent create(Context context, ParcelableStatus status, int timelineType) {
- final TweetEvent event = new TweetEvent();
- event.markStart(context);
- event.setId(status.id);
- event.setUserId(status.user_id);
- event.setTimelineType(timelineType);
- event.setTweetType(HotMobiLogger.getTweetType(status));
- return event;
+ public long getAccountId() {
+ return accountId;
}
- public interface Action {
- int OPEN = 0;
- int RETWEET = 1;
- int FAVORITE = 2;
+ public enum Action {
+ OPEN("open"), RETWEET("retweet"), FAVORITE("favorite"), UNFAVORITE("unfavorite"), UNKNOWN("unknown");
- int UNFAVORITE =-2;
+ private final String value;
+
+ Action(String value) {
+ this.value = value;
+ }
+
+ public static Action parse(String action) {
+ if (OPEN.value.equalsIgnoreCase(action)) {
+ return OPEN;
+ } else if (RETWEET.value.equalsIgnoreCase(action)) {
+ return RETWEET;
+ } else if (FAVORITE.value.equalsIgnoreCase(action)) {
+ return FAVORITE;
+ } else if (UNFAVORITE.value.equalsIgnoreCase(action)) {
+ return UNFAVORITE;
+ }
+ return UNKNOWN;
+ }
+
+
+ public static class TweetActionConverter extends StringBasedTypeConverter {
+
+ @Override
+ public Action getFromString(String string) {
+ return Action.parse(string);
+ }
+
+ @Override
+ public String convertToString(Action action) {
+ if (action == null) return null;
+ return action.value;
+ }
+ }
}
}
diff --git a/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetType.java b/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetType.java
index 8b64a0ed0..fd3607756 100644
--- a/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetType.java
+++ b/twidere/src/main/java/edu/tsinghua/hotmobi/model/TweetType.java
@@ -19,12 +19,71 @@
package edu.tsinghua.hotmobi.model;
+import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter;
+
+import org.mariotaku.twidere.model.ParcelableMedia;
+import org.mariotaku.twidere.model.ParcelableStatus;
+
/**
* Created by mariotaku on 15/8/13.
*/
-public interface TweetType {
- int TEXT = 0;
- int PHOTO = 1;
- int VIDEO = 2;
- int OTHER = 3;
+public enum TweetType {
+ TEXT("text"), PHOTO("photo"), VIDEO("video"), OTHER("other");
+
+ public static TweetType getTweetType(ParcelableStatus status) {
+ if (status.media != null) {
+ boolean hasImage = false;
+ for (ParcelableMedia media : status.media) {
+ switch (media.type) {
+ case ParcelableMedia.TYPE_ANIMATED_GIF:
+ case ParcelableMedia.TYPE_CARD_ANIMATED_GIF:
+ case ParcelableMedia.TYPE_VIDEO:
+ return VIDEO;
+ case ParcelableMedia.TYPE_IMAGE: {
+ hasImage = true;
+ break;
+ }
+ }
+ }
+ if (hasImage) {
+ return PHOTO;
+ }
+ }
+ return TEXT;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ private final String value;
+
+ TweetType(String value) {
+ this.value = value;
+ }
+
+ public static TweetType parse(String type) {
+ if (TEXT.value.equalsIgnoreCase(type)) {
+ return TEXT;
+ } else if (PHOTO.value.equalsIgnoreCase(type)) {
+ return PHOTO;
+ } else if (VIDEO.value.equalsIgnoreCase(type)) {
+ return VIDEO;
+ }
+ return OTHER;
+ }
+
+ public static class TweetTypeConverter extends StringBasedTypeConverter {
+
+ @Override
+ public TweetType getFromString(String string) {
+ return TweetType.parse(string);
+ }
+
+ @Override
+ public String convertToString(TweetType tweetType) {
+ if (tweetType == null) return null;
+ return tweetType.value;
+ }
+ }
}
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 7685e9a35..d50aced95 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
@@ -114,6 +114,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import edu.tsinghua.hotmobi.HotMobiLogger;
+import edu.tsinghua.hotmobi.model.SessionEvent;
import edu.tsinghua.spice.Utilies.NetworkStateUtil;
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
@@ -168,6 +170,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
private ControlBarShowHideHelper mControlBarShowHideHelper = new ControlBarShowHideHelper(this);
private int mTabColumns;
private View mActionBarContainer;
+ private SessionEvent mSessionEvent;
public void closeAccountsDrawer() {
if (mDrawerLayout == null) return;
@@ -450,12 +453,14 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
final Bus bus = TwidereApplication.getInstance(this).getMessageBus();
assert bus != null;
bus.register(this);
- // spice
+ // BEGIN HotMobi
SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_APP, "App Launch" + "," + Build.MODEL
+ "," + "mediaPreview=" + mPreferences.getBoolean(KEY_MEDIA_PREVIEW, false));
SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_ONLAUNCH, "App Launch"
+ "," + NetworkStateUtil.getConnectedType(this) + "," + Build.MODEL);
- //end
+ SessionEvent event = SessionEvent.create(this);
+ mSessionEvent = event;
+ // END HotMobi
mReadStateManager.registerOnSharedPreferenceChangeListener(mReadStateChangeListener);
updateUnreadCount();
}
@@ -488,11 +493,15 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
mPreferences.edit().putInt(KEY_SAVED_TAB_POSITION, mViewPager.getCurrentItem()).apply();
sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONSTOP));
- // spice
+ // BEGIN HotMobi
+ final SessionEvent event = mSessionEvent;
+ event.markEnd();
+ HotMobiLogger.getInstance(this).log(event);
+
SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_APP, "App Stop");
SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_ONLAUNCH, "App Stop" + ","
+ NetworkStateUtil.getConnectedType(this) + "," + Build.MODEL);
- //end
+ // END HotMobi
super.onStop();
}
diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsContentRecyclerViewFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsContentRecyclerViewFragment.java
index 54cdb57a2..ac573621e 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsContentRecyclerViewFragment.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsContentRecyclerViewFragment.java
@@ -52,6 +52,8 @@ import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereColorUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
+import org.mariotaku.twidere.view.iface.IExtendedView;
+import org.mariotaku.twidere.view.themed.AccentSwipeRefreshLayout;
/**
* Comment, blah, blah, blah.
@@ -179,10 +181,10 @@ public abstract class AbsContentRecyclerViewFragment extends AbsContentRecyclerViewFr
}
};
+ private OnScrollListener mHotMobiScrollTracker = new OnScrollListener() {
+
+ private long mFirstVisibleId = -1;
+ private int mFirstVisiblePosition = -1;
+ private int mScrollState;
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
+ final int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
+ if (firstVisiblePosition != mFirstVisiblePosition) {
+ //noinspection unchecked
+ final AbsStatusesAdapter adapter = (AbsStatusesAdapter) recyclerView.getAdapter();
+ final ParcelableStatus status = adapter.getStatus(firstVisiblePosition);
+ if (status != null) {
+ final long id = status.id, accountId = status.account_id;
+ if (id != mFirstVisibleId) {
+ final ScrollRecord record = ScrollRecord.create(id, System.currentTimeMillis(), mScrollState);
+ HotMobiLogger.getInstance(getActivity()).log(accountId, record);
+ }
+ mFirstVisibleId = id;
+ }
+ }
+ mFirstVisiblePosition = firstVisiblePosition;
+ }
+
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ mScrollState = newState;
+ }
+ };
+
protected AbsStatusesFragment() {
mStatusesBusCallback = createMessageBusCallback();
}
@@ -259,8 +293,9 @@ public abstract class AbsStatusesFragment extends AbsContentRecyclerViewFr
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMedia(getActivity(), status, media, options);
// BEGIN HotMobi
- final MediaEvent event = MediaEvent.create(getActivity(), status, media, 0, adapter.isMediaPreviewEnabled());
- HotMobiLogger.getInstance(getActivity()).log(event);
+ final MediaEvent event = MediaEvent.create(getActivity(), status, media, TimelineType.OTHER,
+ adapter.isMediaPreviewEnabled());
+ HotMobiLogger.getInstance(getActivity()).log(status.account_id, event);
// END HotMobi
}
@@ -345,6 +380,7 @@ public abstract class AbsStatusesFragment extends AbsContentRecyclerViewFr
super.onStart();
final RecyclerView recyclerView = getRecyclerView();
recyclerView.addOnScrollListener(mOnScrollListener);
+ recyclerView.addOnScrollListener(mHotMobiScrollTracker);
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
assert bus != null;
bus.register(mStatusesBusCallback);
@@ -356,6 +392,7 @@ public abstract class AbsStatusesFragment extends AbsContentRecyclerViewFr
assert bus != null;
bus.unregister(mStatusesBusCallback);
final RecyclerView recyclerView = getRecyclerView();
+ recyclerView.removeOnScrollListener(mHotMobiScrollTracker);
recyclerView.removeOnScrollListener(mOnScrollListener);
super.onStop();
}
diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/StatusFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/StatusFragment.java
index 91ef6ce4e..07f7651ce 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/StatusFragment.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/StatusFragment.java
@@ -124,6 +124,7 @@ import java.util.Locale;
import edu.tsinghua.hotmobi.HotMobiLogger;
import edu.tsinghua.hotmobi.model.MediaEvent;
+import edu.tsinghua.hotmobi.model.TimelineType;
import edu.tsinghua.hotmobi.model.TweetEvent;
/**
@@ -294,9 +295,9 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMedia(getActivity(), status, media, options);
- MediaEvent event = MediaEvent.create(getActivity(), status, media, 0,
+ MediaEvent event = MediaEvent.create(getActivity(), status, media, TimelineType.OTHER,
mStatusAdapter.isMediaPreviewEnabled());
- HotMobiLogger.getInstance(getActivity()).log(event);
+ HotMobiLogger.getInstance(getActivity()).log(status.account_id, event);
}
@Override
@@ -374,9 +375,9 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMediaDirectly(getActivity(), accountId, status, media, status.media, options);
// BEGIN HotMobi
- MediaEvent event = MediaEvent.create(getActivity(), status, media, 0,
+ MediaEvent event = MediaEvent.create(getActivity(), status, media, TimelineType.OTHER,
mStatusAdapter.isMediaPreviewEnabled());
- HotMobiLogger.getInstance(getActivity()).log(event);
+ HotMobiLogger.getInstance(getActivity()).log(status.account_id, event);
// END HotMobi
}
@@ -526,7 +527,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
mStatusAdapter.setReplies(null);
loadReplies(status);
loadConversation(status);
- final TweetEvent event = TweetEvent.create(getActivity(), status, 0);
+ final TweetEvent event = TweetEvent.create(getActivity(), status, TimelineType.OTHER);
event.setAction(TweetEvent.Action.OPEN);
mStatusEvent = event;
} else {
@@ -867,6 +868,9 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
status.user_screen_name, null);
break;
}
+ case R.id.quote_original_link: {
+ Utils.openStatus(adapter.getContext(), status.account_id, status.quote_id);
+ }
}
}
@@ -902,6 +906,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
favoritesContainer.setOnClickListener(this);
retweetedByView.setOnClickListener(this);
locationView.setOnClickListener(this);
+ quoteOriginalLink.setOnClickListener(this);
final float defaultTextSize = adapter.getTextSize();
nameView.setTextSize(defaultTextSize * 1.25f);
@@ -1574,7 +1579,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final TweetEvent event = mStatusEvent;
if (event == null) return;
event.markEnd();
- HotMobiLogger.getInstance(getActivity()).log(event);
+ HotMobiLogger.getInstance(getActivity()).log(event.getAccountId(), event);
}
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 d4d493ff7..1e98316de 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/util/AsyncTwitterWrapper.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/AsyncTwitterWrapper.java
@@ -107,6 +107,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
import edu.tsinghua.hotmobi.HotMobiLogger;
import edu.tsinghua.hotmobi.model.RefreshEvent;
+import edu.tsinghua.hotmobi.model.TimelineType;
import edu.tsinghua.hotmobi.model.TweetEvent;
public class AsyncTwitterWrapper extends TwitterWrapper {
@@ -920,9 +921,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
// BEGIN HotMobi
- final TweetEvent event = TweetEvent.create(getContext(), status, 0);
+ final TweetEvent event = TweetEvent.create(getContext(), status, TimelineType.OTHER);
event.setAction(TweetEvent.Action.FAVORITE);
- HotMobiLogger.getInstance(getContext()).log(event);
+ HotMobiLogger.getInstance(getContext()).log(account_id, event);
// END HotMobi
@@ -1556,9 +1557,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final ParcelableStatus status = result.getData();
// BEGIN HotMobi
- final TweetEvent event = TweetEvent.create(getContext(), status, 0);
+ final TweetEvent event = TweetEvent.create(getContext(), status, TimelineType.OTHER);
event.setAction(TweetEvent.Action.UNFAVORITE);
- HotMobiLogger.getInstance(getContext()).log(event);
+ HotMobiLogger.getInstance(getContext()).log(account_id, event);
// END HotMobi
@@ -1998,6 +1999,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return Statuses.CONTENT_URI;
}
+ @Override
+ protected TimelineType getTimelineType() {
+ return TimelineType.HOME;
+ }
+
@Override
protected void onPostExecute(final List result) {
@@ -2056,6 +2062,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return Mentions.CONTENT_URI;
}
+ @Override
+ protected TimelineType getTimelineType() {
+ return TimelineType.INTERACTIONS;
+ }
+
@Override
protected void onPostExecute(final List result) {
super.onPostExecute(result);
@@ -2202,8 +2213,8 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
countCur.close();
// BEGIN HotMobi
- final RefreshEvent event = RefreshEvent.create(mContext, statusIds, 0);
- HotMobiLogger.getInstance(mContext).log(event);
+ final RefreshEvent event = RefreshEvent.create(mContext, statusIds, getTimelineType());
+ HotMobiLogger.getInstance(mContext).log(accountId, event);
// END HotMobi
// Insert a gap.
@@ -2220,6 +2231,8 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
+ protected abstract TimelineType getTimelineType();
+
@SafeVarargs
@Override
protected final void onProgressUpdate(TwitterListResponse... values) {
@@ -2626,9 +2639,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
// BEGIN HotMobi
- final TweetEvent event = TweetEvent.create(getContext(), status, 0);
+ final TweetEvent event = TweetEvent.create(getContext(), status, TimelineType.OTHER);
event.setAction(TweetEvent.Action.RETWEET);
- HotMobiLogger.getInstance(getContext()).log(event);
+ HotMobiLogger.getInstance(getContext()).log(account_id, event);
// END HotMobi
diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/StatusCodeMessageUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/StatusCodeMessageUtils.java
index 977ad10ae..6f5c2e608 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/util/StatusCodeMessageUtils.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/StatusCodeMessageUtils.java
@@ -22,7 +22,6 @@ package org.mariotaku.twidere.util;
import android.content.Context;
import android.util.SparseIntArray;
-import org.apache.http.HttpStatus;
import org.mariotaku.twidere.R;
public class StatusCodeMessageUtils {
@@ -53,7 +52,8 @@ public class StatusCodeMessageUtils {
TWITTER_ERROR_CODE_MESSAGES.put(STATUS_IS_DUPLICATE, R.string.error_twitter_187);
TWITTER_ERROR_CODE_MESSAGES.put(193, R.string.error_twitter_193);
TWITTER_ERROR_CODE_MESSAGES.put(215, R.string.error_twitter_215);
- HTTP_STATUS_CODE_MESSAGES.put(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED, R.string.error_http_407);
+
+ HTTP_STATUS_CODE_MESSAGES.put(407, R.string.error_http_407);
}
public static boolean containsHttpStatus(final int code) {
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 ffecc97fb..d48b421cf 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java
@@ -114,7 +114,6 @@ import android.widget.Toast;
import com.bluelinelabs.logansquare.LoganSquare;
import org.apache.commons.lang3.ArrayUtils;
-import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -3696,8 +3695,8 @@ public final class Utils implements Constants {
try {
final String template = "http://translate.google.com/#%s|%s|%s";
final String sourceLang = "auto";
- final String targetLang = URLEncoder.encode(locale.getLanguage(), HTTP.UTF_8);
- final String text = URLEncoder.encode(status.text_unescaped, HTTP.UTF_8);
+ final String targetLang = URLEncoder.encode(locale.getLanguage(), "UTF-8");
+ final String text = URLEncoder.encode(status.text_unescaped, "UTF-8");
final Uri uri = Uri.parse(String.format(Locale.ROOT, template, sourceLang, targetLang, text));
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/InetAddressUtils.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/InetAddressUtils.java
new file mode 100644
index 000000000..6df666fef
--- /dev/null
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/InetAddressUtils.java
@@ -0,0 +1,111 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.mariotaku.twidere.util.net;
+
+import java.util.regex.Pattern;
+
+/**
+ * A collection of utilities relating to InetAddresses.
+ *
+ * @since 4.0
+ */
+public class InetAddressUtils {
+ private InetAddressUtils() {
+ }
+
+ private static final String IPV4_BASIC_PATTERN_STRING =
+ "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + // initial 3 fields, 0-255 followed by .
+ "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255
+ private static final Pattern IPV4_PATTERN =
+ Pattern.compile("^" + IPV4_BASIC_PATTERN_STRING + "$");
+ private static final Pattern IPV4_MAPPED_IPV6_PATTERN = // TODO does not allow for redundant leading zeros
+ Pattern.compile("^::[fF]{4}:" + IPV4_BASIC_PATTERN_STRING + "$");
+ private static final Pattern IPV6_STD_PATTERN =
+ Pattern.compile(
+ "^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");
+ private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
+ Pattern.compile(
+ "^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + // 0-6 hex fields
+ "::" +
+ "(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields
+ /*
+ * The above pattern is not totally rigorous as it allows for more than 7 hex fields in total
+ */
+ private static final char COLON_CHAR = ':';
+ // Must not have more than 7 colons (i.e. 8 fields)
+ private static final int MAX_COLON_COUNT = 7;
+
+ /**
+ * Checks whether the parameter is a valid IPv4 address
+ *
+ * @param input the address string to check for validity
+ * @return true if the input parameter is a valid IPv4 address
+ */
+ public static boolean isIPv4Address(final String input) {
+ return IPV4_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv4MappedIPv64Address(final String input) {
+ return IPV4_MAPPED_IPV6_PATTERN.matcher(input).matches();
+ }
+
+ /**
+ * Checks whether the parameter is a valid standard (non-compressed) IPv6 address
+ *
+ * @param input the address string to check for validity
+ * @return true if the input parameter is a valid standard (non-compressed) IPv6 address
+ */
+ public static boolean isIPv6StdAddress(final String input) {
+ return IPV6_STD_PATTERN.matcher(input).matches();
+ }
+
+ /**
+ * Checks whether the parameter is a valid compressed IPv6 address
+ *
+ * @param input the address string to check for validity
+ * @return true if the input parameter is a valid compressed IPv6 address
+ */
+ public static boolean isIPv6HexCompressedAddress(final String input) {
+ int colonCount = 0;
+ for (int i = 0; i < input.length(); i++) {
+ if (input.charAt(i) == COLON_CHAR) {
+ colonCount++;
+ }
+ }
+ return colonCount <= MAX_COLON_COUNT && IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
+ }
+
+ /**
+ * Checks whether the parameter is a valid IPv6 address (including compressed).
+ *
+ * @param input the address string to check for validity
+ * @return true if the input parameter is a valid standard or compressed IPv6 address
+ */
+ public static boolean isIPv6Address(final String input) {
+ return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
+ }
+}
\ No newline at end of file
diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java
index 2a2eb46dd..11244a91e 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java
@@ -27,7 +27,6 @@ import android.util.LruCache;
import com.squareup.okhttp.internal.Network;
-import org.apache.http.conn.util.InetAddressUtils;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.util.HostsFileParser;
diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/themed/AccentSwipeRefreshLayout.java b/twidere/src/main/java/org/mariotaku/twidere/view/themed/AccentSwipeRefreshLayout.java
index cf54e1cd7..e2985e938 100644
--- a/twidere/src/main/java/org/mariotaku/twidere/view/themed/AccentSwipeRefreshLayout.java
+++ b/twidere/src/main/java/org/mariotaku/twidere/view/themed/AccentSwipeRefreshLayout.java
@@ -21,16 +21,24 @@ package org.mariotaku.twidere.view.themed;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
+import android.view.MotionEvent;
+import org.mariotaku.twidere.view.iface.IExtendedView;
import org.mariotaku.twidere.view.iface.IThemeAccentView;
/**
* Created by mariotaku on 15/4/25.
*/
-public class AccentSwipeRefreshLayout extends SwipeRefreshLayout implements IThemeAccentView {
+public class AccentSwipeRefreshLayout extends SwipeRefreshLayout implements IThemeAccentView, IExtendedView {
+
+ private TouchInterceptor mTouchInterceptor;
+ private OnSizeChangedListener mOnSizeChangedListener;
+ private OnFitSystemWindowsListener mOnFitSystemWindowsListener;
+
public AccentSwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -43,4 +51,63 @@ public class AccentSwipeRefreshLayout extends SwipeRefreshLayout implements IThe
public void setAccentTintColor(@NonNull ColorStateList color) {
setColorSchemeColors(color.getDefaultColor());
}
+
+ @Override
+ public final boolean dispatchTouchEvent(@NonNull final MotionEvent event) {
+ if (mTouchInterceptor != null) {
+ final boolean ret = mTouchInterceptor.dispatchTouchEvent(this, event);
+ if (ret) return true;
+ }
+ return super.dispatchTouchEvent(event);
+ }
+
+ @Override
+ public final boolean onInterceptTouchEvent(final MotionEvent event) {
+ if (mTouchInterceptor != null) {
+ final boolean ret = mTouchInterceptor.onInterceptTouchEvent(this, event);
+ if (ret) return true;
+ }
+ return super.onInterceptTouchEvent(event);
+ }
+
+ @Override
+ public void setOnFitSystemWindowsListener(OnFitSystemWindowsListener listener) {
+ mOnFitSystemWindowsListener = listener;
+ }
+
+ @Override
+ public final void setOnSizeChangedListener(final OnSizeChangedListener listener) {
+ mOnSizeChangedListener = listener;
+ }
+
+ @Override
+ public final void setTouchInterceptor(final TouchInterceptor listener) {
+ mTouchInterceptor = listener;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected boolean fitSystemWindows(@NonNull Rect insets) {
+ if (mOnFitSystemWindowsListener != null) {
+ mOnFitSystemWindowsListener.onFitSystemWindows(insets);
+ }
+ return super.fitSystemWindows(insets);
+ }
+
+ @Override
+ public final boolean onTouchEvent(@NonNull final MotionEvent event) {
+ if (mTouchInterceptor != null) {
+ final boolean ret = mTouchInterceptor.onTouchEvent(this, event);
+ if (ret) return true;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected final void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ if (mOnSizeChangedListener != null) {
+ mOnSizeChangedListener.onSizeChanged(this, w, h, oldw, oldh);
+ }
+ }
}