removed action mode view
limits disk cache to 384 mb, it will be configurable in the future
This commit is contained in:
parent
470ecc3726
commit
939c78e5cb
|
@ -7,10 +7,10 @@ android:
|
|||
- tools
|
||||
|
||||
# The BuildTools version used by your project
|
||||
- build-tools-22.0.1
|
||||
- build-tools-23.0.0
|
||||
|
||||
# The SDK version used to compile your project
|
||||
- android-22
|
||||
- android-23
|
||||
|
||||
# Additional components
|
||||
- extra-google-google_play_services
|
||||
|
|
|
@ -39,11 +39,11 @@ android {
|
|||
dependencies {
|
||||
apt 'com.bluelinelabs:logansquare-compiler:1.1.0'
|
||||
apt 'com.hannesdorfmann.parcelableplease:processor:1.0.1'
|
||||
compile 'com.android.support:support-annotations:22.2.1'
|
||||
compile 'com.android.support:support-v4:22.2.1'
|
||||
compile 'com.android.support:support-annotations:23.0.0'
|
||||
compile 'com.android.support:support-v4:23.0.0'
|
||||
compile 'com.bluelinelabs:logansquare:1.1.0'
|
||||
compile 'org.apache.commons:commons-lang3:3.4'
|
||||
compile 'com.github.mariotaku:RestFu:0.9'
|
||||
compile 'com.github.mariotaku:RestFu:0.9.1'
|
||||
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
|
||||
compile 'com.github.mariotaku:SQLiteQB:ef3f596199'
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
|
|
@ -912,12 +912,14 @@ public interface TwidereDataStore {
|
|||
|
||||
String MUTING = "muting";
|
||||
|
||||
String RETWEET_ENABLED = "retweet_enabled";
|
||||
|
||||
String[] COLUMNS = {_ID, ACCOUNT_ID, USER_ID, FOLLOWING, FOLLOWED_BY, BLOCKING,
|
||||
BLOCKED_BY, MUTING};
|
||||
BLOCKED_BY, MUTING, RETWEET_ENABLED};
|
||||
|
||||
String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_INT, TYPE_BOOLEAN_DEFAULT_FALSE,
|
||||
TYPE_BOOLEAN_DEFAULT_FALSE, TYPE_BOOLEAN_DEFAULT_FALSE, TYPE_BOOLEAN_DEFAULT_FALSE,
|
||||
TYPE_BOOLEAN_DEFAULT_FALSE};
|
||||
TYPE_BOOLEAN_DEFAULT_FALSE, TYPE_BOOLEAN_DEFAULT_TRUE};
|
||||
}
|
||||
|
||||
interface UnreadCounts extends BaseColumns {
|
||||
|
|
|
@ -19,27 +19,33 @@
|
|||
|
||||
package edu.tsinghua.hotmobi;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import edu.tsinghua.hotmobi.model.BaseEvent;
|
||||
import edu.tsinghua.hotmobi.model.LatLng;
|
||||
import edu.tsinghua.hotmobi.model.LinkEvent;
|
||||
import edu.tsinghua.hotmobi.model.MediaEvent;
|
||||
import edu.tsinghua.hotmobi.model.NetworkEvent;
|
||||
import edu.tsinghua.hotmobi.model.RefreshEvent;
|
||||
import edu.tsinghua.hotmobi.model.ScrollRecord;
|
||||
import edu.tsinghua.hotmobi.model.SessionEvent;
|
||||
import edu.tsinghua.hotmobi.model.TweetEvent;
|
||||
|
||||
|
@ -50,15 +56,25 @@ public class HotMobiLogger {
|
|||
|
||||
public static final long ACCOUNT_ID_NOT_NEEDED = -1;
|
||||
|
||||
private static final String LOGTAG = "HotMobiLogger";
|
||||
public static final String LOGTAG = "HotMobiLogger";
|
||||
public static final long UPLOAD_INTERVAL_MILLIS = TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS);
|
||||
public static final String LAST_UPLOAD_TIME = "last_upload_time";
|
||||
final static SimpleDateFormat DATE_FORMAT;
|
||||
|
||||
static {
|
||||
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
private final Application mApplication;
|
||||
private final Executor mExecutor;
|
||||
|
||||
public HotMobiLogger() {
|
||||
public HotMobiLogger(Application application) {
|
||||
mApplication = application;
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
private static String getLogFilename(BaseEvent event) {
|
||||
public static String getLogFilename(Object event) {
|
||||
if (event instanceof RefreshEvent) {
|
||||
return "refresh";
|
||||
} else if (event instanceof SessionEvent) {
|
||||
|
@ -67,8 +83,14 @@ public class HotMobiLogger {
|
|||
return "tweet";
|
||||
} else if (event instanceof MediaEvent) {
|
||||
return "media";
|
||||
} else if (event instanceof LinkEvent) {
|
||||
return "link";
|
||||
} else if (event instanceof NetworkEvent) {
|
||||
return "network";
|
||||
} else if (event instanceof ScrollRecord) {
|
||||
return "scroll";
|
||||
}
|
||||
return null;
|
||||
throw new UnsupportedOperationException("Unknown event type " + event);
|
||||
}
|
||||
|
||||
public static String getInstallationSerialId(Context context) {
|
||||
|
@ -95,21 +117,39 @@ public class HotMobiLogger {
|
|||
return new LatLng(location.getLatitude(), location.getLongitude());
|
||||
}
|
||||
|
||||
public void log(long accountId, final Object event) {
|
||||
public static File getLogFile(Context context, long accountId, String type) {
|
||||
final File logsDir = getLogsDir(context);
|
||||
final File todayLogDir = new File(logsDir, DATE_FORMAT.format(new Date()));
|
||||
if (!todayLogDir.exists()) {
|
||||
todayLogDir.mkdirs();
|
||||
}
|
||||
final String logFilename;
|
||||
if (accountId > 0) {
|
||||
logFilename = type + "_" + accountId + ".log";
|
||||
} else {
|
||||
logFilename = type + ".log";
|
||||
}
|
||||
return new File(todayLogDir, logFilename);
|
||||
}
|
||||
|
||||
mExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Log.d(LOGTAG, LoganSquare.serialize(event));
|
||||
} catch (IOException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
public static File getLogsDir(Context context) {
|
||||
return new File(context.getFilesDir(), "hotmobi");
|
||||
}
|
||||
|
||||
public static long getLastUploadTime(final Context context) {
|
||||
final SharedPreferences prefs = context.getSharedPreferences("spice_data_profiling", Context.MODE_PRIVATE);
|
||||
return prefs.getLong(LAST_UPLOAD_TIME, -1);
|
||||
}
|
||||
|
||||
public void log(long accountId, final Object event) {
|
||||
mExecutor.execute(new WriteLogTask(mApplication, accountId, event));
|
||||
}
|
||||
|
||||
public void log(Object event) {
|
||||
log(ACCOUNT_ID_NOT_NEEDED, event);
|
||||
}
|
||||
|
||||
public void logList(List<?> events, long accountId, String type) {
|
||||
mExecutor.execute(new WriteLogTask(mApplication, accountId, type, events));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package edu.tsinghua.spice.Utilies;
|
||||
package edu.tsinghua.hotmobi;
|
||||
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify;
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
|
@ -17,44 +17,37 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.view;
|
||||
package edu.tsinghua.hotmobi;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.internal.widget.ActionBarContextView;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.preference.Preference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/1/16.
|
||||
* Created by mariotaku on 15/8/28.
|
||||
*/
|
||||
public class TwidereActionBarContextView extends ActionBarContextView {
|
||||
public class UploadLogsPreferences extends Preference {
|
||||
|
||||
private int mItemColor;
|
||||
|
||||
public TwidereActionBarContextView(Context context) {
|
||||
public UploadLogsPreferences(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public TwidereActionBarContextView(Context context, AttributeSet attrs) {
|
||||
public UploadLogsPreferences(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public TwidereActionBarContextView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
public UploadLogsPreferences(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMode(ActionMode mode) {
|
||||
super.initForMode(mode);
|
||||
if (mItemColor != 0) {
|
||||
ThemeUtils.setActionBarContextViewColor(this, mItemColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemColor(int itemColor) {
|
||||
mItemColor = itemColor;
|
||||
ThemeUtils.setActionBarContextViewColor(this, itemColor);
|
||||
protected void onClick() {
|
||||
final Context context = getContext();
|
||||
final SharedPreferences prefs = context.getSharedPreferences("spice_data_profiling", Context.MODE_PRIVATE);
|
||||
prefs.edit().remove(HotMobiLogger.LAST_UPLOAD_TIME).apply();
|
||||
AsyncTask.execute(new UploadLogsTask(context.getApplicationContext()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package edu.tsinghua.hotmobi;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
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.twidere.util.TwitterAPIFactory;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/8/27.
|
||||
*/
|
||||
public class UploadLogsTask implements Runnable {
|
||||
|
||||
private final Context context;
|
||||
private final RestHttpClient client;
|
||||
|
||||
public UploadLogsTask(Context context) {
|
||||
this.context = context;
|
||||
this.client = TwitterAPIFactory.getDefaultHttpClient(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
final SharedPreferences prefs = context.getSharedPreferences("spice_data_profiling", Context.MODE_PRIVATE);
|
||||
|
||||
if (prefs.contains(HotMobiLogger.LAST_UPLOAD_TIME)) {
|
||||
final long lastUpload = prefs.getLong(HotMobiLogger.LAST_UPLOAD_TIME, System.currentTimeMillis());
|
||||
final double deltaDays = (System.currentTimeMillis() - lastUpload) /
|
||||
(double) HotMobiLogger.UPLOAD_INTERVAL_MILLIS;
|
||||
if (deltaDays < 1) {
|
||||
SpiceProfilingUtil.log("Last uploaded was conducted in 1 day ago.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadLogs()) {
|
||||
prefs.edit().putLong(HotMobiLogger.LAST_UPLOAD_TIME, System.currentTimeMillis()).apply();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean uploadLogs() {
|
||||
final String uuid = HotMobiLogger.getInstallationSerialId(context);
|
||||
final File logsDir = HotMobiLogger.getLogsDir(context);
|
||||
boolean hasErrors = false;
|
||||
final String todayDir = HotMobiLogger.DATE_FORMAT.format(new Date());
|
||||
final FilenameFilter filter = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String filename) {
|
||||
return !filename.equalsIgnoreCase(todayDir);
|
||||
}
|
||||
};
|
||||
for (File dayLogsDir : logsDir.listFiles(filter)) {
|
||||
boolean succeeded = true;
|
||||
for (File logFile : dayLogsDir.listFiles()) {
|
||||
FileTypedData body = null;
|
||||
RestHttpResponse response = null;
|
||||
try {
|
||||
final RestHttpRequest.Builder builder = new RestHttpRequest.Builder();
|
||||
builder.method(POST.METHOD);
|
||||
builder.url("http://oahu.hot-mobile.org/usage/upload");
|
||||
final List<Pair<String, String>> headers = new ArrayList<>();
|
||||
headers.add(Pair.create("X-HotMobi-UUID", uuid));
|
||||
headers.add(Pair.create("X-HotMobi-Date", dayLogsDir.getName()));
|
||||
headers.add(Pair.create("X-HotMobi-FileName", logFile.getName()));
|
||||
builder.headers(headers);
|
||||
body = new FileTypedData(logFile);
|
||||
builder.body(body);
|
||||
response = client.execute(builder.build());
|
||||
if (response.isSuccessful()) {
|
||||
succeeded &= logFile.delete();
|
||||
}
|
||||
response.close();
|
||||
} catch (IOException e) {
|
||||
Log.w(HotMobiLogger.LOGTAG, e);
|
||||
succeeded = false;
|
||||
hasErrors = true;
|
||||
} finally {
|
||||
Utils.closeSilently(body);
|
||||
Utils.closeSilently(response);
|
||||
}
|
||||
}
|
||||
if (succeeded) {
|
||||
dayLogsDir.delete();
|
||||
}
|
||||
}
|
||||
return hasErrors;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package edu.tsinghua.hotmobi;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/8/23.
|
||||
*/
|
||||
public class WriteLogTask implements Runnable, Constants {
|
||||
|
||||
private static final byte[] LF = {'\n'};
|
||||
|
||||
private final Context context;
|
||||
private final long accountId;
|
||||
private final String type;
|
||||
private final List<?> events;
|
||||
|
||||
public WriteLogTask(Context context, long accountId, Object event) {
|
||||
this(context, accountId, HotMobiLogger.getLogFilename(event), Collections.singletonList(event));
|
||||
}
|
||||
|
||||
public WriteLogTask(Context context, long accountId, String type, List<?> events) {
|
||||
this.context = context;
|
||||
this.accountId = accountId;
|
||||
this.type = type;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
if (!prefs.getBoolean(KEY_USAGE_STATISTICS, false)) return;
|
||||
RandomAccessFile raf = null;
|
||||
FileChannel fc = null;
|
||||
try {
|
||||
raf = new RandomAccessFile(HotMobiLogger.getLogFile(context, accountId, type), "rw");
|
||||
fc = raf.getChannel();
|
||||
final FileLock lock = fc.lock();
|
||||
for (Object event : events) {
|
||||
final byte[] bytes = LoganSquare.serialize(event).getBytes("UTF-8");
|
||||
final long start = raf.length();
|
||||
final ByteBuffer bb;
|
||||
if (start == 0) {
|
||||
// Don't write line break
|
||||
bb = ByteBuffer.allocate(bytes.length);
|
||||
} else {
|
||||
bb = ByteBuffer.allocate(bytes.length + LF.length);
|
||||
bb.put(LF);
|
||||
bb.position(LF.length);
|
||||
}
|
||||
bb.put(bytes);
|
||||
bb.rewind();
|
||||
fc.position(start);
|
||||
while (bb.hasRemaining()) {
|
||||
fc.write(bb);
|
||||
}
|
||||
}
|
||||
lock.release();
|
||||
} catch (IOException e) {
|
||||
Log.w(HotMobiLogger.LOGTAG, e);
|
||||
} finally {
|
||||
Utils.closeSilently(fc);
|
||||
Utils.closeSilently(raf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package edu.tsinghua.hotmobi.model;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
import edu.tsinghua.hotmobi.TypeMappingUtil;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/8/20.
|
||||
*/
|
||||
@JsonObject
|
||||
public class LinkEvent extends BaseEvent {
|
||||
|
||||
@JsonField(name = "link")
|
||||
String link;
|
||||
@JsonField(name = "type")
|
||||
String type;
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static LinkEvent create(Context context, String link, int typeInt) {
|
||||
final LinkEvent event = new LinkEvent();
|
||||
event.markStart(context);
|
||||
event.setLink(link);
|
||||
event.setType(TypeMappingUtil.getLinkType(typeInt));
|
||||
return event;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package edu.tsinghua.hotmobi.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/8/20.
|
||||
*/
|
||||
@JsonObject
|
||||
public class NetworkEvent extends BaseEvent {
|
||||
|
||||
@JsonField(name = "network_type")
|
||||
int networkType;
|
||||
|
||||
|
||||
public static NetworkEvent create(Context context) {
|
||||
final NetworkEvent event = new NetworkEvent();
|
||||
event.markStart(context);
|
||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
final NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo();
|
||||
if (activeNetworkInfo != null) {
|
||||
event.setNetworkType(activeNetworkInfo.getType());
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
public void setNetworkType(int networkType) {
|
||||
this.networkType = networkType;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,13 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
|
|||
public class ScrollRecord {
|
||||
@JsonField(name = "id")
|
||||
long id;
|
||||
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
@JsonField(name = "account_id")
|
||||
long accountId;
|
||||
@JsonField(name = "timestamp")
|
||||
long timestamp;
|
||||
@JsonField(name = "scroll_state")
|
||||
|
@ -46,9 +53,10 @@ public class ScrollRecord {
|
|||
this.scrollState = scrollState;
|
||||
}
|
||||
|
||||
public static ScrollRecord create(long id, long timestamp, int scrollState) {
|
||||
public static ScrollRecord create(long id, long accountId, long timestamp, int scrollState) {
|
||||
final ScrollRecord record = new ScrollRecord();
|
||||
record.setId(id);
|
||||
record.setAccountId(accountId);
|
||||
record.setTimestamp(timestamp);
|
||||
record.setScrollState(scrollState);
|
||||
return record;
|
||||
|
|
|
@ -57,9 +57,6 @@ public class TweetEvent extends BaseEvent {
|
|||
return event;
|
||||
}
|
||||
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public void setAction(Action action) {
|
||||
this.action = action;
|
||||
|
@ -85,9 +82,14 @@ public class TweetEvent extends BaseEvent {
|
|||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(long accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
|
||||
public enum Action {
|
||||
OPEN("open"), RETWEET("retweet"), FAVORITE("favorite"), UNFAVORITE("unfavorite"), UNKNOWN("unknown");
|
||||
OPEN("open"), RETWEET("retweet"), FAVORITE("favorite"), UNFAVORITE("unfavorite"),
|
||||
TWEET("tweet"), UNKNOWN("unknown");
|
||||
|
||||
private final String value;
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.copyStream;
|
||||
|
@ -32,9 +32,6 @@ import static org.mariotaku.twidere.util.Utils.copyStream;
|
|||
|
||||
public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> implements Constants {
|
||||
|
||||
public static final long UPLOAD_INTERVAL_MILLIS = TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS);
|
||||
public static final String LAST_UPLOAD_TIME = "last_upload_time";
|
||||
|
||||
private static final String PROFILE_SERVER_URL = "http://spice.hot-mobile.org/spice/usage";
|
||||
|
||||
private final Context context;
|
||||
|
@ -91,9 +88,9 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> implem
|
|||
|
||||
final SharedPreferences prefs = context.getSharedPreferences("spice_data_profiling", Context.MODE_PRIVATE);
|
||||
|
||||
if (prefs.contains(LAST_UPLOAD_TIME)) {
|
||||
final long lastUpload = prefs.getLong(LAST_UPLOAD_TIME, System.currentTimeMillis());
|
||||
final double deltaDays = (System.currentTimeMillis() - lastUpload) / (double) UPLOAD_INTERVAL_MILLIS;
|
||||
if (prefs.contains(HotMobiLogger.LAST_UPLOAD_TIME)) {
|
||||
final long lastUpload = prefs.getLong(HotMobiLogger.LAST_UPLOAD_TIME, System.currentTimeMillis());
|
||||
final double deltaDays = (System.currentTimeMillis() - lastUpload) / (double) HotMobiLogger.UPLOAD_INTERVAL_MILLIS;
|
||||
if (deltaDays < 1) {
|
||||
SpiceProfilingUtil.log("Last uploaded was conducted in 1 day ago.");
|
||||
return null;
|
||||
|
@ -103,7 +100,7 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> implem
|
|||
final File root = context.getFilesDir();
|
||||
final File[] spiceFiles = root.listFiles(new SpiceFileFilter());
|
||||
uploadToServer(spiceFiles);
|
||||
prefs.edit().putLong(LAST_UPLOAD_TIME, System.currentTimeMillis()).apply();
|
||||
prefs.edit().putLong(HotMobiLogger.LAST_UPLOAD_TIME, System.currentTimeMillis()).apply();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -149,8 +146,4 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> implem
|
|||
}
|
||||
}
|
||||
|
||||
public static long getLastUploadTime(final Context context) {
|
||||
final SharedPreferences prefs = context.getSharedPreferences("spice_data_profiling", Context.MODE_PRIVATE);
|
||||
return prefs.getLong(LAST_UPLOAD_TIME, -1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,10 @@ import android.annotation.SuppressLint;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
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;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Created by Denny C. Ng on 2/20/15.
|
||||
|
@ -54,43 +45,4 @@ public class SpiceProfilingUtil {
|
|||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void profile(final Context context, final long account_id, final String text) {
|
||||
profile(context, account_id + "_" + 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 persistedDeviceId = prefs.getString(Constants.KEY_DEVICE_SERIAL, null);
|
||||
final String serial = String.valueOf(Build.SERIAL).replaceAll("[^\\w\\d]", "");
|
||||
final String uuid;
|
||||
if (!TextUtils.isEmpty(persistedDeviceId)) {
|
||||
uuid = persistedDeviceId.replaceAll("[^\\w\\d]", "");
|
||||
} else if (!TextUtils.isEmpty(serial)) {
|
||||
uuid = serial;
|
||||
prefs.edit().putString(Constants.KEY_DEVICE_SERIAL, serial).apply();
|
||||
} else {
|
||||
uuid = UUID.randomUUID().toString().replaceAll("[^\\w\\d]", "");
|
||||
prefs.edit().putString(Constants.KEY_DEVICE_SERIAL, uuid).apply();
|
||||
}
|
||||
final String filename = uuid + "_" + name + ".spi";
|
||||
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(text + "," + System.currentTimeMillis() + "\n");
|
||||
bw.flush();
|
||||
fos.close();
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import static org.mariotaku.twidere.annotation.Preference.Type.STRING;
|
|||
public interface Constants extends TwidereConstants {
|
||||
|
||||
String DATABASES_NAME = "twidere.sqlite";
|
||||
int DATABASES_VERSION = 105;
|
||||
int DATABASES_VERSION = 107;
|
||||
|
||||
int MENU_GROUP_STATUS_EXTENSION = 10;
|
||||
int MENU_GROUP_COMPOSE_EXTENSION = 11;
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.mariotaku.restfu.http.Endpoint;
|
|||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.api.twitter.TwitterOAuth;
|
||||
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.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
|
@ -237,7 +238,7 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity {
|
|||
consumerSecret = defConsumerSecret;
|
||||
}
|
||||
try {
|
||||
final Endpoint endpoint = new Endpoint(TwitterAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", "oauth"));
|
||||
final OAuthEndpoint endpoint = new OAuthEndpoint(TwitterAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api", null));
|
||||
final Authorization auth = new OAuthAuthorization(consumerKey, consumerSecret);
|
||||
final TwitterOAuth twitter = TwitterAPIFactory.getInstance(mActivity, endpoint, auth, TwitterOAuth.class);
|
||||
return twitter.getRequestToken(OAUTH_CALLBACK_OOB);
|
||||
|
|
|
@ -454,11 +454,7 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
|
|||
assert bus != null;
|
||||
bus.register(this);
|
||||
// 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);
|
||||
SessionEvent event = SessionEvent.create(this);
|
||||
final SessionEvent event = SessionEvent.create(this);
|
||||
mSessionEvent = event;
|
||||
// END HotMobi
|
||||
mReadStateManager.registerOnSharedPreferenceChangeListener(mReadStateChangeListener);
|
||||
|
@ -497,10 +493,6 @@ public class HomeActivity extends BaseAppCompatActivity implements OnClickListen
|
|||
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 HotMobi
|
||||
super.onStop();
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import android.support.annotation.Nullable;
|
|||
import android.support.multidex.MultiDexApplication;
|
||||
|
||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
||||
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
|
||||
|
@ -67,11 +67,13 @@ import org.mariotaku.twidere.util.UserColorNameManager;
|
|||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.VideoLoader;
|
||||
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper;
|
||||
import org.mariotaku.twidere.util.imageloader.ReadOnlyDiskLRUNameCache;
|
||||
import org.mariotaku.twidere.util.imageloader.TwidereImageDownloader;
|
||||
import org.mariotaku.twidere.util.imageloader.URLFileNameGenerator;
|
||||
import org.mariotaku.twidere.util.net.TwidereHostAddressResolver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
|
||||
|
@ -337,11 +339,13 @@ public class TwidereApplication extends MultiDexApplication implements Constants
|
|||
private DiskCache createDiskCache(final String dirName) {
|
||||
final File cacheDir = getBestCacheDir(this, dirName);
|
||||
final File fallbackCacheDir = getInternalCacheDir(this, dirName);
|
||||
// final LruDiscCache discCache = new LruDiscCache(cacheDir, new URLFileNameGenerator(), 384 *
|
||||
// 1024 * 1024);
|
||||
// discCache.setReserveCacheDir(fallbackCacheDir);
|
||||
// return discCache;
|
||||
return new UnlimitedDiskCache(cacheDir, fallbackCacheDir, new URLFileNameGenerator());
|
||||
final URLFileNameGenerator fileNameGenerator = new URLFileNameGenerator();
|
||||
try {
|
||||
return new LruDiskCache(cacheDir, fallbackCacheDir, fileNameGenerator,
|
||||
384 * 1024 * 1024, 0);
|
||||
} catch (IOException e) {
|
||||
return new ReadOnlyDiskLRUNameCache(cacheDir, fallbackCacheDir, fileNameGenerator);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeAsyncTask() {
|
||||
|
@ -356,6 +360,6 @@ public class TwidereApplication extends MultiDexApplication implements Constants
|
|||
@NonNull
|
||||
public HotMobiLogger getHotMobiLogger() {
|
||||
if (mHotMobiLogger != null) return mHotMobiLogger;
|
||||
return mHotMobiLogger = new HotMobiLogger();
|
||||
return mHotMobiLogger = new HotMobiLogger(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.mariotaku.twidere.fragment.support;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
|
|
|
@ -21,6 +21,8 @@ import android.view.KeyEvent;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.desmond.asyncmanager.AsyncManager;
|
||||
import com.desmond.asyncmanager.TaskRunnable;
|
||||
import com.squareup.otto.Bus;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
|
@ -38,10 +40,15 @@ import org.mariotaku.twidere.util.ReadStateManager;
|
|||
import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
|
||||
import org.mariotaku.twidere.util.RecyclerViewUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.imageloader.PauseRecyclerViewOnScrollListener;
|
||||
import org.mariotaku.twidere.util.message.StatusListChangedEvent;
|
||||
import org.mariotaku.twidere.view.holder.GapViewHolder;
|
||||
import org.mariotaku.twidere.view.holder.StatusViewHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
import edu.tsinghua.hotmobi.model.MediaEvent;
|
||||
import edu.tsinghua.hotmobi.model.ScrollRecord;
|
||||
|
@ -77,7 +84,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
getFragmentManager(), getTwitterWrapper(), status, item);
|
||||
}
|
||||
};
|
||||
private OnScrollListener mOnScrollListener = new OnScrollListener() {
|
||||
private final OnScrollListener mOnScrollListener = new OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
|
@ -86,10 +93,12 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
}
|
||||
}
|
||||
};
|
||||
private OnScrollListener mPauseOnScrollListener;
|
||||
|
||||
private OnScrollListener mHotMobiScrollTracker = new OnScrollListener() {
|
||||
private final OnScrollListener mHotMobiScrollTracker = new OnScrollListener() {
|
||||
|
||||
private long mFirstVisibleId = -1;
|
||||
public List<ScrollRecord> mRecords;
|
||||
private long mFirstVisibleId = -1, mFirstVisibleAccountId = -1;
|
||||
private int mFirstVisiblePosition = -1;
|
||||
private int mScrollState;
|
||||
|
||||
|
@ -103,11 +112,13 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
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);
|
||||
if (id != mFirstVisibleId || accountId != mFirstVisibleAccountId) {
|
||||
if (mRecords == null) mRecords = new ArrayList<>();
|
||||
mRecords.add(ScrollRecord.create(id, accountId, System.currentTimeMillis(),
|
||||
mScrollState));
|
||||
}
|
||||
mFirstVisibleId = id;
|
||||
mFirstVisibleAccountId = accountId;
|
||||
}
|
||||
}
|
||||
mFirstVisiblePosition = firstVisiblePosition;
|
||||
|
@ -116,9 +127,17 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
mScrollState = newState;
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
if (mRecords != null) {
|
||||
HotMobiLogger.getInstance(getActivity()).logList(mRecords, HotMobiLogger.ACCOUNT_ID_NOT_NEEDED, "scroll");
|
||||
}
|
||||
mRecords = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private OnScrollListener mActiveHotMobiScrollTracker;
|
||||
|
||||
protected AbsStatusesFragment() {
|
||||
mStatusesBusCallback = createMessageBusCallback();
|
||||
}
|
||||
|
@ -213,6 +232,18 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
return onCreateStatusesLoader(getActivity(), args, fromUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
|
||||
if (isVisibleToUser) {
|
||||
final LinearLayoutManager layoutManager = getLayoutManager();
|
||||
if (layoutManager != null) {
|
||||
saveReadPosition(layoutManager.findFirstVisibleItemPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onLoadFinished(Loader<Data> loader, Data data) {
|
||||
final AbsStatusesAdapter<Data> adapter = getAdapter();
|
||||
|
@ -380,7 +411,27 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
super.onStart();
|
||||
final RecyclerView recyclerView = getRecyclerView();
|
||||
recyclerView.addOnScrollListener(mOnScrollListener);
|
||||
recyclerView.addOnScrollListener(mHotMobiScrollTracker);
|
||||
recyclerView.addOnScrollListener(mPauseOnScrollListener);
|
||||
final TaskRunnable<Object, Boolean, RecyclerView> task = new TaskRunnable<Object, Boolean, RecyclerView>() {
|
||||
@Override
|
||||
public Boolean doLongOperation(Object params) throws InterruptedException {
|
||||
final Context context = getContext();
|
||||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
if (!prefs.getBoolean(KEY_USAGE_STATISTICS, false)) return false;
|
||||
final File logFile = HotMobiLogger.getLogFile(context, HotMobiLogger.ACCOUNT_ID_NOT_NEEDED, "scroll");
|
||||
return logFile.length() < 131072;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callback(RecyclerView recyclerView, Boolean result) {
|
||||
if (result) {
|
||||
recyclerView.addOnScrollListener(mActiveHotMobiScrollTracker = mHotMobiScrollTracker);
|
||||
}
|
||||
}
|
||||
};
|
||||
task.setResultHandler(recyclerView);
|
||||
AsyncManager.runBackgroundTask(task);
|
||||
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
|
||||
assert bus != null;
|
||||
bus.register(mStatusesBusCallback);
|
||||
|
@ -392,7 +443,11 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
assert bus != null;
|
||||
bus.unregister(mStatusesBusCallback);
|
||||
final RecyclerView recyclerView = getRecyclerView();
|
||||
recyclerView.removeOnScrollListener(mHotMobiScrollTracker);
|
||||
if (mActiveHotMobiScrollTracker != null) {
|
||||
recyclerView.removeOnScrollListener(mActiveHotMobiScrollTracker);
|
||||
}
|
||||
mActiveHotMobiScrollTracker = null;
|
||||
recyclerView.removeOnScrollListener(mPauseOnScrollListener);
|
||||
recyclerView.removeOnScrollListener(mOnScrollListener);
|
||||
super.onStop();
|
||||
}
|
||||
|
@ -425,6 +480,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
|
|||
adapter, this);
|
||||
|
||||
adapter.setListener(this);
|
||||
mPauseOnScrollListener = new PauseRecyclerViewOnScrollListener(adapter.getMediaLoader().getImageLoader(), false, true);
|
||||
|
||||
final Bundle loaderArgs = new Bundle(getArguments());
|
||||
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
|
||||
|
|
|
@ -61,7 +61,6 @@ public class StatusRepliesLoader extends UserMentionsLoader {
|
|||
}
|
||||
} else {
|
||||
final List<Status> statuses = super.getStatuses(twitter, paging);
|
||||
// TODO null check
|
||||
for (final Status status : statuses) {
|
||||
if (status.getInReplyToStatusId() == mInReplyToStatusId) {
|
||||
result.add(status);
|
||||
|
|
|
@ -23,18 +23,18 @@ import android.content.BroadcastReceiver;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mariotaku.twidere.BuildConfig;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.util.AsyncTaskUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.net.NetworkUsageUtils;
|
||||
|
||||
import edu.tsinghua.spice.Task.SpiceAsyUploadTask;
|
||||
import edu.tsinghua.spice.Utilies.NetworkStateUtil;
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
import edu.tsinghua.hotmobi.UploadLogsTask;
|
||||
import edu.tsinghua.hotmobi.model.NetworkEvent;
|
||||
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.startRefreshServiceIfNeeded;
|
||||
|
@ -53,13 +53,10 @@ public class ConnectivityStateReceiver extends BroadcastReceiver implements Cons
|
|||
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
if (prefs.getBoolean(KEY_USAGE_STATISTICS, false) && prefs.getBoolean(KEY_SETTINGS_WIZARD_COMPLETED, false)) {
|
||||
//spice
|
||||
SpiceProfilingUtil.profile(context, SpiceProfilingUtil.FILE_NAME_ONWIFI, NetworkStateUtil.getConnectedType(context));
|
||||
final Location location = Utils.getCachedLocation(context);
|
||||
if (location != null) {
|
||||
SpiceProfilingUtil.profile(context, SpiceProfilingUtil.FILE_NAME_LOCATION, location.getTime() + ","
|
||||
+ location.getLatitude() + "," + location.getLongitude() + "," + location.getProvider());
|
||||
}
|
||||
// BEGIN HotMobi
|
||||
final NetworkEvent event = NetworkEvent.create(context);
|
||||
HotMobiLogger.getInstance(context).log(event);
|
||||
// END HotMobi
|
||||
}
|
||||
final int networkType = Utils.getActiveNetworkType(context.getApplicationContext());
|
||||
NetworkUsageUtils.setNetworkType(networkType);
|
||||
|
@ -67,10 +64,11 @@ public class ConnectivityStateReceiver extends BroadcastReceiver implements Cons
|
|||
final boolean isCharging = SpiceProfilingUtil.isCharging(context.getApplicationContext());
|
||||
if (isWifi && isCharging) {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
final long lastSuccessfulTime = SpiceAsyUploadTask.getLastUploadTime(context);
|
||||
if ((currentTime - lastSuccessfulTime) > SpiceAsyUploadTask.UPLOAD_INTERVAL_MILLIS) {
|
||||
AsyncTaskUtils.executeTask(new SpiceAsyUploadTask(context));
|
||||
final long lastSuccessfulTime = HotMobiLogger.getLastUploadTime(context);
|
||||
if ((currentTime - lastSuccessfulTime) > HotMobiLogger.UPLOAD_INTERVAL_MILLIS) {
|
||||
AsyncTask.execute(new UploadLogsTask(context.getApplicationContext()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,14 +35,13 @@ public class SecretCodeBroadcastReceiver extends BroadcastReceiver implements In
|
|||
public void onReceive(final Context context, final Intent intent) {
|
||||
final Intent testIntent = new Intent(context, SettingsActivity.class);
|
||||
final String cls = SettingsDetailsFragment.class.getName();
|
||||
final String title = context.getString(R.string.hidden_settings);
|
||||
final Bundle args = new Bundle();
|
||||
args.putInt(EXTRA_RESID, R.xml.preferences_hidden);
|
||||
args.putString(EXTRA_SETTINGS_INTENT_ACTION, INTENT_ACTION_HIDDEN_SETTINGS_ENTRY);
|
||||
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, cls);
|
||||
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
|
||||
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
|
||||
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_SHORT_TITLE, title);
|
||||
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, R.string.hidden_settings);
|
||||
testIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_SHORT_TITLE, R.string.hidden_settings);
|
||||
testIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(testIntent);
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ import org.mariotaku.twidere.model.MediaUploadResult;
|
|||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableDirectMessage;
|
||||
import org.mariotaku.twidere.model.ParcelableLocation;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.ParcelableMediaUpdate;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
||||
|
@ -97,8 +96,9 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
|
||||
import edu.tsinghua.spice.Utilies.TypeMappingUtil;
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
import edu.tsinghua.hotmobi.model.TimelineType;
|
||||
import edu.tsinghua.hotmobi.model.TweetEvent;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
import static org.mariotaku.twidere.util.ContentValuesCreator.createMessageDraft;
|
||||
|
@ -330,28 +330,20 @@ public class BackgroundOperationService extends IntentService implements Constan
|
|||
final List<Long> failedAccountIds = ListUtils.fromArray(ParcelableAccount.getAccountIds(item.accounts));
|
||||
|
||||
for (final SingleResponse<ParcelableStatus> response : result) {
|
||||
|
||||
if (response.getData() == null) {
|
||||
final ParcelableStatus data = response.getData();
|
||||
if (data == null) {
|
||||
failed = true;
|
||||
if (exception == null) {
|
||||
exception = response.getException();
|
||||
}
|
||||
} else if (response.getData().account_id > 0) {
|
||||
failedAccountIds.remove(response.getData().account_id);
|
||||
//spice
|
||||
if (response.getData().media == null) {
|
||||
SpiceProfilingUtil.log(response.getData().id + ",Tweet," + response.getData().account_id + ","
|
||||
+ response.getData().in_reply_to_user_id + "," + response.getData().in_reply_to_status_id);
|
||||
SpiceProfilingUtil.profile(this.getBaseContext(), response.getData().account_id, response.getData().id + ",Tweet," + response.getData().account_id + ","
|
||||
+ response.getData().in_reply_to_user_id + "," + response.getData().in_reply_to_status_id);
|
||||
} else
|
||||
for (final ParcelableMedia spiceMedia : response.getData().media) {
|
||||
SpiceProfilingUtil.log(response.getData().id + ",Media," + response.getData().account_id + ","
|
||||
+ response.getData().in_reply_to_user_id + "," + response.getData().in_reply_to_status_id + "," + spiceMedia.media_url + "," + TypeMappingUtil.getMediaType(spiceMedia.type));
|
||||
SpiceProfilingUtil.profile(this.getBaseContext(), response.getData().account_id, response.getData().id + ",Media," + response.getData().account_id + ","
|
||||
+ response.getData().in_reply_to_user_id + "," + response.getData().in_reply_to_status_id + "," + spiceMedia.media_url + "," + TypeMappingUtil.getMediaType(spiceMedia.type));
|
||||
}
|
||||
//end
|
||||
} else if (data.account_id > 0) {
|
||||
failedAccountIds.remove(data.account_id);
|
||||
// BEGIN HotMobi
|
||||
final TweetEvent event = TweetEvent.create(BackgroundOperationService.this, data,
|
||||
TimelineType.OTHER);
|
||||
event.setAction(TweetEvent.Action.TWEET);
|
||||
HotMobiLogger.getInstance(BackgroundOperationService.this).log(data.account_id, event);
|
||||
// END HotMobi
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ import org.mariotaku.twidere.model.ParcelableUser;
|
|||
import org.mariotaku.twidere.model.ParcelableUserList;
|
||||
import org.mariotaku.twidere.model.SingleResponse;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.*;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Inbox;
|
||||
|
@ -837,9 +837,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
|
||||
}
|
||||
// I bet you don't want to see this user in your auto complete list.
|
||||
//TODO insert to blocked users data
|
||||
// final Expression where = Expression.equals(CachedUsers.USER_ID, user_id);
|
||||
// mResolver.delete(CachedUsers.CONTENT_URI, where.getSQL(), null);
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(CachedRelationships.ACCOUNT_ID, account_id);
|
||||
values.put(CachedRelationships.USER_ID, user_id);
|
||||
values.put(CachedRelationships.BLOCKING, true);
|
||||
mResolver.insert(CachedRelationships.CONTENT_URI, values);
|
||||
return SingleResponse.getInstance(new ParcelableUser(user, account_id), null);
|
||||
} catch (final TwitterException e) {
|
||||
return SingleResponse.getInstance(null, e);
|
||||
|
|
|
@ -82,6 +82,10 @@ public class MediaLoaderWrapper implements Constants {
|
|||
mDashboardProfileImageDisplayOptions = dashboardProfileOptsBuilder.build();
|
||||
}
|
||||
|
||||
public ImageLoader getImageLoader() {
|
||||
return mImageLoader;
|
||||
}
|
||||
|
||||
public void clearFileCache() {
|
||||
mImageLoader.clearDiskCache();
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ import org.mariotaku.twidere.Constants;
|
|||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify.OnLinkClickListener;
|
||||
|
||||
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
|
||||
import edu.tsinghua.spice.Utilies.TypeMappingUtil;
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger;
|
||||
import edu.tsinghua.hotmobi.model.LinkEvent;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.openStatus;
|
||||
import static org.mariotaku.twidere.util.Utils.openTweetSearch;
|
||||
|
@ -56,9 +56,10 @@ public class OnLinkClickHandler implements OnLinkClickListener, Constants {
|
|||
final boolean sensitive, int start, int end) {
|
||||
if (manager != null && manager.isActive()) return;
|
||||
if (!isPrivateData()) {
|
||||
//spice
|
||||
SpiceProfilingUtil.profile(context, accountId, accountId + ",Visit," + link + "," + TypeMappingUtil.getLinkType(type));
|
||||
//end
|
||||
// BEGIN HotMobi
|
||||
final LinkEvent event = LinkEvent.create(context, link, type);
|
||||
HotMobiLogger.getInstance(context).log(accountId, event);
|
||||
// END HotMobi
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
|
|
@ -37,7 +37,6 @@ import android.view.Window;
|
|||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.activity.iface.IThemedActivity;
|
||||
import org.mariotaku.twidere.view.TintedStatusNativeActionModeAwareLayout;
|
||||
|
||||
|
@ -49,8 +48,6 @@ public class TwidereActionModeForChildListener implements TintedStatusNativeActi
|
|||
private final IThemedActivity mThemed;
|
||||
private final AppCompatCallback mAppCompatCallback;
|
||||
private final Window mWindow;
|
||||
private final boolean mIsFloating;
|
||||
private final boolean mUsePopup;
|
||||
|
||||
private ActionMode mActionMode;
|
||||
public ActionBarContextView mActionModeView;
|
||||
|
@ -62,8 +59,6 @@ public class TwidereActionModeForChildListener implements TintedStatusNativeActi
|
|||
mThemed = activity;
|
||||
mWindow = mActivity.getWindow();
|
||||
mAppCompatCallback = callback;
|
||||
mIsFloating = ThemeUtils.isWindowFloating(mActivity, activity.getCurrentThemeResourceId());
|
||||
mUsePopup = usePopup;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,39 +99,35 @@ public class TwidereActionModeForChildListener implements TintedStatusNativeActi
|
|||
final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
|
||||
|
||||
if (mActionModeView == null) {
|
||||
if (mIsFloating && mUsePopup) {
|
||||
// Use the action bar theme.
|
||||
final Context actionBarContext;
|
||||
actionBarContext = ThemeUtils.getActionBarThemedContext(mActivity, mThemed.getCurrentThemeResourceId(),
|
||||
mThemed.getCurrentThemeColor());
|
||||
// Use the action bar theme.
|
||||
final Context actionBarContext;
|
||||
actionBarContext = ThemeUtils.getActionBarThemedContext(mActivity, mThemed.getCurrentThemeResourceId(),
|
||||
mThemed.getCurrentThemeColor());
|
||||
|
||||
mActionModeView = new ActionBarContextView(actionBarContext);
|
||||
mActionModePopup = new PopupWindow(actionBarContext, null,
|
||||
android.support.v7.appcompat.R.attr.actionModePopupWindowStyle);
|
||||
mActionModePopup.setContentView(mActionModeView);
|
||||
mActionModePopup.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mActionModeView = new ActionBarContextView(actionBarContext);
|
||||
mActionModePopup = new PopupWindow(actionBarContext, null,
|
||||
android.support.v7.appcompat.R.attr.actionModePopupWindowStyle);
|
||||
mActionModePopup.setContentView(mActionModeView);
|
||||
mActionModePopup.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
|
||||
final TypedValue outValue = new TypedValue();
|
||||
actionBarContext.getTheme().resolveAttribute(
|
||||
android.support.v7.appcompat.R.attr.actionBarSize, outValue, true);
|
||||
final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
|
||||
actionBarContext.getResources().getDisplayMetrics());
|
||||
mActionModeView.setContentHeight(height);
|
||||
ThemeUtils.setActionBarContextViewBackground(mActionModeView,
|
||||
mThemed.getCurrentThemeResourceId(), mThemed.getCurrentThemeColor(),
|
||||
mThemed.getCurrentThemeBackgroundOption(), false);
|
||||
mActionModePopup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mShowActionModePopup = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mActionModePopup.showAtLocation(
|
||||
mWindow.getDecorView(),
|
||||
Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
mActionModeView = (ActionBarContextView) mWindow.findViewById(R.id.action_context_bar);
|
||||
}
|
||||
final TypedValue outValue = new TypedValue();
|
||||
actionBarContext.getTheme().resolveAttribute(
|
||||
android.support.v7.appcompat.R.attr.actionBarSize, outValue, true);
|
||||
final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
|
||||
actionBarContext.getResources().getDisplayMetrics());
|
||||
mActionModeView.setContentHeight(height);
|
||||
ThemeUtils.setActionBarContextViewBackground(mActionModeView,
|
||||
mThemed.getCurrentThemeResourceId(), mThemed.getCurrentThemeColor(),
|
||||
mThemed.getCurrentThemeBackgroundOption(), false);
|
||||
mActionModePopup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mShowActionModePopup = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mActionModePopup.showAtLocation(
|
||||
mWindow.getDecorView(),
|
||||
Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (mActionModeView != null) {
|
||||
|
|
|
@ -90,7 +90,8 @@ public final class DatabaseUpgradeHelper {
|
|||
}
|
||||
|
||||
public static void safeUpgrade(final SQLiteDatabase db, final String table, final String[] newColNames,
|
||||
final String[] newColTypes, final boolean dropDirectly, final Map<String, String> colAliases, final Constraint... constraints) {
|
||||
final String[] newColTypes, final boolean dropDirectly,
|
||||
final Map<String, String> colAliases, final Constraint... constraints) {
|
||||
safeUpgrade(db, table, newColNames, newColTypes, dropDirectly, colAliases, OnConflict.REPLACE, constraints);
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,8 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
db.execSQL(createTable(CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true));
|
||||
db.execSQL(createTable(CachedStatuses.TABLE_NAME, CachedStatuses.COLUMNS, CachedStatuses.TYPES, true));
|
||||
db.execSQL(createTable(CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, CachedHashtags.TYPES, true));
|
||||
db.execSQL(createTable(CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true));
|
||||
db.execSQL(createTable(CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true,
|
||||
createConflictReplaceConstraint(CachedRelationships.ACCOUNT_ID, CachedRelationships.USER_ID)));
|
||||
db.execSQL(createTable(Filters.Users.TABLE_NAME, Filters.Users.COLUMNS, Filters.Users.TYPES, true));
|
||||
db.execSQL(createTable(Filters.Keywords.TABLE_NAME, Filters.Keywords.COLUMNS, Filters.Keywords.TYPES, true));
|
||||
db.execSQL(createTable(Filters.Sources.TABLE_NAME, Filters.Sources.COLUMNS, Filters.Sources.TYPES, true));
|
||||
|
@ -98,7 +99,8 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
db.execSQL(createTable(Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, true));
|
||||
db.execSQL(createTable(SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true));
|
||||
db.execSQL(createTable(SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true));
|
||||
db.execSQL(createTable(NetworkUsages.TABLE_NAME, NetworkUsages.COLUMNS, NetworkUsages.TYPES, true, createNetworkUsagesConstraint()));
|
||||
db.execSQL(createTable(NetworkUsages.TABLE_NAME, NetworkUsages.COLUMNS, NetworkUsages.TYPES, true,
|
||||
createConflictReplaceConstraint(NetworkUsages.TIME_IN_HOURS, NetworkUsages.REQUEST_NETWORK, NetworkUsages.REQUEST_TYPE)));
|
||||
|
||||
createViews(db);
|
||||
createTriggers(db);
|
||||
|
@ -108,8 +110,8 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
db.endTransaction();
|
||||
}
|
||||
|
||||
private Constraint createNetworkUsagesConstraint() {
|
||||
return Constraint.unique(new Columns(NetworkUsages.TIME_IN_HOURS, NetworkUsages.REQUEST_NETWORK, NetworkUsages.REQUEST_TYPE), OnConflict.IGNORE);
|
||||
private Constraint createConflictReplaceConstraint(String... columns) {
|
||||
return Constraint.unique(new Columns(columns), OnConflict.IGNORE);
|
||||
}
|
||||
|
||||
private void createIndices(SQLiteDatabase db) {
|
||||
|
@ -234,7 +236,8 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
safeUpgrade(db, CachedUsers.TABLE_NAME, CachedUsers.COLUMNS, CachedUsers.TYPES, true, null);
|
||||
safeUpgrade(db, CachedStatuses.TABLE_NAME, CachedStatuses.COLUMNS, CachedStatuses.TYPES, true, null);
|
||||
safeUpgrade(db, CachedHashtags.TABLE_NAME, CachedHashtags.COLUMNS, CachedHashtags.TYPES, true, null);
|
||||
safeUpgrade(db, CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true, null);
|
||||
safeUpgrade(db, CachedRelationships.TABLE_NAME, CachedRelationships.COLUMNS, CachedRelationships.TYPES, true, null,
|
||||
createConflictReplaceConstraint(CachedRelationships.ACCOUNT_ID, CachedRelationships.USER_ID));
|
||||
safeUpgrade(db, Filters.Users.TABLE_NAME, Filters.Users.COLUMNS, Filters.Users.TYPES,
|
||||
oldVersion < 49, null);
|
||||
safeUpgrade(db, Filters.Keywords.TABLE_NAME, Filters.Keywords.COLUMNS, Filters.Keywords.TYPES,
|
||||
|
@ -253,7 +256,7 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
safeUpgrade(db, SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true, null);
|
||||
safeUpgrade(db, SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true, null);
|
||||
safeUpgrade(db, NetworkUsages.TABLE_NAME, NetworkUsages.COLUMNS, NetworkUsages.TYPES, true, null,
|
||||
createNetworkUsagesConstraint());
|
||||
createConflictReplaceConstraint(NetworkUsages.TIME_IN_HOURS, NetworkUsages.REQUEST_NETWORK, NetworkUsages.REQUEST_TYPE));
|
||||
db.beginTransaction();
|
||||
createViews(db);
|
||||
createTriggers(db);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.imageloader;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
|
||||
public class PauseRecyclerViewOnScrollListener extends RecyclerView.OnScrollListener {
|
||||
private ImageLoader imageLoader;
|
||||
private final boolean pauseOnScroll;
|
||||
private final boolean pauseOnFling;
|
||||
|
||||
public PauseRecyclerViewOnScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {
|
||||
this.imageLoader = imageLoader;
|
||||
this.pauseOnScroll = pauseOnScroll;
|
||||
this.pauseOnFling = pauseOnFling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
switch (newState) {
|
||||
case RecyclerView.SCROLL_STATE_IDLE:
|
||||
this.imageLoader.resume();
|
||||
break;
|
||||
case RecyclerView.SCROLL_STATE_DRAGGING:
|
||||
if (this.pauseOnScroll) {
|
||||
this.imageLoader.pause();
|
||||
}
|
||||
break;
|
||||
case RecyclerView.SCROLL_STATE_SETTLING:
|
||||
if (this.pauseOnFling) {
|
||||
this.imageLoader.pause();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util.imageloader;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.BaseDiskCache;
|
||||
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
|
||||
import com.nostra13.universalimageloader.utils.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/8/28.
|
||||
*/
|
||||
public class ReadOnlyDiskLRUNameCache extends BaseDiskCache {
|
||||
public ReadOnlyDiskLRUNameCache(File cacheDir) {
|
||||
super(cacheDir);
|
||||
}
|
||||
|
||||
public ReadOnlyDiskLRUNameCache(File cacheDir, File reserveCacheDir) {
|
||||
super(cacheDir, reserveCacheDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(String imageUri, Bitmap bitmap) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(String imageUri) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File getFile(String imageUri) {
|
||||
String fileName = fileNameGenerator.generate(imageUri) + ".0";
|
||||
File dir = cacheDir;
|
||||
if ((!cacheDir.exists()) && (!cacheDir.mkdirs()) &&
|
||||
(reserveCacheDir != null) && ((reserveCacheDir.exists()) || (reserveCacheDir.mkdirs()))) {
|
||||
dir = reserveCacheDir;
|
||||
}
|
||||
return new File(dir, fileName);
|
||||
}
|
||||
|
||||
public ReadOnlyDiskLRUNameCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {
|
||||
super(cacheDir, reserveCacheDir, fileNameGenerator);
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.mariotaku.twidere.activity.iface.IThemedActivity;
|
|||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
||||
/**
|
||||
* Wraps context with ActionBar context
|
||||
* Created by mariotaku on 15/4/28.
|
||||
*/
|
||||
public class TwidereActionBarContainer extends ActionBarContainer {
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<org.mariotaku.twidere.view.TwidereToolbar
|
||||
android:id="@+id/action_bar"
|
||||
style="?attr/toolbarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:navigationContentDescription="@string/abc_action_bar_up_description" />
|
||||
app:navigationContentDescription="@string/abc_action_bar_up_description"
|
||||
tools:ignore="PrivateResource" />
|
||||
|
||||
<org.mariotaku.twidere.view.TwidereActionBarContextView
|
||||
android:id="@+id/action_context_bar"
|
||||
style="?attr/actionModeStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:visibility="gone" />
|
||||
</merge>
|
|
@ -22,11 +22,4 @@
|
|||
app:tabHorizontalPadding="@dimen/element_spacing_normal" />
|
||||
</org.mariotaku.twidere.view.TwidereToolbar>
|
||||
|
||||
<org.mariotaku.twidere.view.TwidereActionBarContextView
|
||||
android:id="@+id/action_context_bar"
|
||||
style="?attr/actionModeStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:visibility="gone" />
|
||||
</merge>
|
|
@ -772,4 +772,5 @@
|
|||
<string name="set_consumer_key_secret_message">Twidere is reaching token limit, you will have to create an app at https://apps.twitter.com/ and paste consumer key and secret below.\nIf you continue using default key, you may not be able to sign in.</string>
|
||||
<string name="send_at">Send at</string>
|
||||
<string name="scheduled_statuses">Scheduled tweets</string>
|
||||
<string name="report_usage_statistics_now">Report usage statistics now</string>
|
||||
</resources>
|
|
@ -28,6 +28,8 @@
|
|||
android:key="status_text_limit"
|
||||
android:title="@string/status_text_limit" />
|
||||
|
||||
<edu.tsinghua.hotmobi.UploadLogsPreferences android:title="@string/report_usage_statistics_now" />
|
||||
|
||||
<Preference android:title="@string/settings_wizard">
|
||||
<intent
|
||||
android:targetClass="org.mariotaku.twidere.activity.SettingsWizardActivity"
|
||||
|
|
Loading…
Reference in New Issue