added network usage
@ -9,7 +9,7 @@ buildscript {
|
||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.9'
|
||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
|
||||
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:1.0.1') {
|
||||
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:1.0.2') {
|
||||
// should be excluded to avoid conflict
|
||||
exclude group: 'xerces'
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ dependencies {
|
||||
compile 'com.android.support:support-v4:22.2.0'
|
||||
compile 'com.bluelinelabs:logansquare:1.1.0'
|
||||
compile 'org.apache.commons:commons-lang3:3.4'
|
||||
compile 'com.github.mariotaku:RestFu:b40c366f1c'
|
||||
compile 'com.github.mariotaku:RestFu:d965fcf941'
|
||||
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
|
||||
compile project(':twidere.component.querybuilder')
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
@ -181,6 +181,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
|
||||
int TABLE_ID_CACHED_STATUSES = 62;
|
||||
int TABLE_ID_CACHED_HASHTAGS = 63;
|
||||
int TABLE_ID_CACHED_RELATIONSHIPS = 64;
|
||||
int TABLE_ID_NETWORK_USAGES = 71;
|
||||
int VIRTUAL_TABLE_ID_DATABASE_READY = 100;
|
||||
int VIRTUAL_TABLE_ID_NOTIFICATIONS = 101;
|
||||
int VIRTUAL_TABLE_ID_PREFERENCES = 102;
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.model;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/6/24.
|
||||
*/
|
||||
public enum RequestType {
|
||||
API("api"), MEDIA("media"), USAGE_STATISTICS("usage_statistics");
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
RequestType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ public interface TwidereDataStore {
|
||||
String TYPE_BOOLEAN_DEFAULT_TRUE = "INTEGER(1) DEFAULT 1";
|
||||
String TYPE_BOOLEAN_DEFAULT_FALSE = "INTEGER(1) DEFAULT 0";
|
||||
String TYPE_TEXT = "TEXT";
|
||||
String TYPE_DOUBLE_NOT_NULL = "DOUBLE NOT NULL";
|
||||
String TYPE_TEXT_NOT_NULL = "TEXT NOT NULL";
|
||||
String TYPE_TEXT_NOT_NULL_UNIQUE = "TEXT NOT NULL UNIQUE";
|
||||
|
||||
@ -914,4 +915,28 @@ public interface TwidereDataStore {
|
||||
Uri CONTENT_URI = Uri.withAppendedPath(UnreadCounts.CONTENT_URI, CONTENT_PATH_SEGMENT);
|
||||
}
|
||||
}
|
||||
|
||||
interface NetworkUsages extends BaseColumns {
|
||||
|
||||
String TABLE_NAME = "network_usages";
|
||||
String CONTENT_PATH = TABLE_NAME;
|
||||
|
||||
Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
|
||||
|
||||
String TIME_IN_HOURS = "time_in_hours";
|
||||
|
||||
String REQUEST_TYPE = "request_type";
|
||||
|
||||
String REQUEST_NETWORK = "request_network";
|
||||
|
||||
String KILOBYTES_SENT = "kilobytes_sent";
|
||||
|
||||
String KILOBYTES_RECEIVED = "kilobytes_received";
|
||||
|
||||
String[] COLUMNS = {_ID, TIME_IN_HOURS, REQUEST_TYPE, REQUEST_NETWORK, KILOBYTES_SENT,
|
||||
KILOBYTES_RECEIVED};
|
||||
|
||||
String[] TYPES = {TYPE_PRIMARY_KEY, TYPE_INT, TYPE_TEXT_NOT_NULL, TYPE_TEXT_NOT_NULL,
|
||||
TYPE_DOUBLE_NOT_NULL, TYPE_DOUBLE_NOT_NULL};
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import org.mariotaku.restfu.http.RestHttpClient;
|
||||
import org.mariotaku.restfu.http.RestHttpRequest;
|
||||
import org.mariotaku.restfu.http.RestHttpResponse;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
import org.mariotaku.twidere.util.HtmlLinkExtractor.HtmlLink;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -352,6 +353,7 @@ public class MediaPreviewUtils {
|
||||
final RestHttpRequest.Builder builder = new RestHttpRequest.Builder();
|
||||
builder.method(GET.METHOD);
|
||||
builder.url(Endpoint.constructUrl(URL_PHOTOZOU_PHOTO_INFO, Pair.create("photo_id", id)));
|
||||
builder.extra(RequestType.MEDIA);
|
||||
final RestHttpResponse response = client.execute(builder.build());
|
||||
final PhotoZouPhotoInfo info = LoganSquare.parse(response.getBody().stream(), PhotoZouPhotoInfo.class);
|
||||
if (info.info != null && info.info.photo != null) {
|
||||
|
@ -453,8 +453,8 @@ public class NyanDrawingHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static interface StarAnimFrames {
|
||||
static final byte[][] FRAME1 = {
|
||||
private interface StarAnimFrames {
|
||||
byte[][] FRAME1 = {
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0
|
||||
},
|
||||
|
@ -23,8 +23,58 @@ package org.mariotaku.querybuilder;
|
||||
* Created by mariotaku on 15/3/30.
|
||||
*/
|
||||
public class Constraint implements SQLLang {
|
||||
private final String name;
|
||||
private final String type;
|
||||
private final SQLQuery constraint;
|
||||
|
||||
public Constraint(String name, String type, SQLQuery constraint) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.constraint = constraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return null;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (name != null) {
|
||||
sb.append("CONSTRAINT ");
|
||||
sb.append(name);
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(type);
|
||||
sb.append(" ");
|
||||
sb.append(constraint.getSQL());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static Constraint unique(String name, Columns columns, OnConflict onConflict) {
|
||||
return new Constraint(name, "UNIQUE", new ColumnConflictConstaint(columns, onConflict));
|
||||
}
|
||||
|
||||
public static Constraint unique(Columns columns, OnConflict onConflict) {
|
||||
return unique(null, columns, onConflict);
|
||||
}
|
||||
|
||||
private static final class ColumnConflictConstaint implements SQLQuery {
|
||||
|
||||
private final Columns columns;
|
||||
private final OnConflict onConflict;
|
||||
|
||||
public ColumnConflictConstaint(Columns columns, OnConflict onConflict) {
|
||||
this.columns = columns;
|
||||
this.onConflict = onConflict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
sb.append(columns.getSQL());
|
||||
sb.append(") ");
|
||||
sb.append("ON CONFLICT ");
|
||||
sb.append(onConflict.getAction());
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.querybuilder;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/6/24.
|
||||
*/
|
||||
public final class RawSQLLang implements SQLLang {
|
||||
|
||||
private final String statement;
|
||||
|
||||
public RawSQLLang(String statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
return statement;
|
||||
}
|
||||
}
|
@ -34,5 +34,5 @@ public interface SQLLang extends Cloneable {
|
||||
*
|
||||
* @return SQL query
|
||||
*/
|
||||
public String getSQL();
|
||||
String getSQL();
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
/**
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* <p/>
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* <p/>
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
@ -13,7 +13,7 @@
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
|
||||
* <p/>
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
@ -21,7 +21,7 @@
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* <p/>
|
||||
* For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
@ -110,6 +110,10 @@ public class SQLQueryBuilder {
|
||||
return new SQLUpdateQuery.Builder().update(onConflict, table);
|
||||
}
|
||||
|
||||
public static SQLUpdateQuery.Builder update(final OnConflict onConflict, final String table) {
|
||||
return update(onConflict, new Table(table));
|
||||
}
|
||||
|
||||
public static SQLInsertQuery.Builder insertInto(final String table) {
|
||||
return insertInto(null, table);
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ public class SetValue implements SQLLang {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public SetValue(String column, SQLLang expression) {
|
||||
this(new Columns.Column(column), expression);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getSQL() {
|
||||
|
@ -35,8 +35,8 @@ public class SQLCreateTableQuery implements SQLQuery {
|
||||
if (newColumns != null && newColumns.length > 0) {
|
||||
sb.append('(');
|
||||
sb.append(Utils.toString(newColumns, ',', true));
|
||||
if (constraints != null) {
|
||||
sb.append(' ');
|
||||
if (constraints != null && constraints.length > 0) {
|
||||
sb.append(", ");
|
||||
sb.append(Utils.toString(constraints, ',', true));
|
||||
sb.append(' ');
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ public class SQLInsertQuery implements SQLQuery {
|
||||
private OnConflict onConflict;
|
||||
private String table;
|
||||
private String[] columns;
|
||||
private SQLSelectQuery select;
|
||||
private String values;
|
||||
|
||||
SQLInsertQuery() {
|
||||
|
||||
@ -21,11 +21,18 @@ public class SQLInsertQuery implements SQLQuery {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("INSERT ");
|
||||
if (onConflict != null) {
|
||||
sb.append(String.format("OR %s ", onConflict.getAction()));
|
||||
sb.append("OR ");
|
||||
sb.append(onConflict.getAction());
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(String.format("INTO %s ", table));
|
||||
sb.append(String.format("(%s) ", Utils.toString(columns, ',', false)));
|
||||
sb.append(String.format("%s ", select.getSQL()));
|
||||
sb.append("INTO ");
|
||||
sb.append(table);
|
||||
sb.append(" (");
|
||||
sb.append(Utils.toString(columns, ',', false));
|
||||
sb.append(") ");
|
||||
sb.append("VALUES (");
|
||||
sb.append(values);
|
||||
sb.append(") ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -38,7 +45,11 @@ public class SQLInsertQuery implements SQLQuery {
|
||||
}
|
||||
|
||||
void setSelect(final SQLSelectQuery select) {
|
||||
this.select = select;
|
||||
this.values = select.getSQL();
|
||||
}
|
||||
|
||||
void setValues(final String... values) {
|
||||
this.values = Utils.toString(values, ',', false);
|
||||
}
|
||||
|
||||
void setTable(final String table) {
|
||||
@ -68,6 +79,18 @@ public class SQLInsertQuery implements SQLQuery {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder values(final String[] values) {
|
||||
checkNotBuilt();
|
||||
query.setValues(values);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder values(final String values) {
|
||||
checkNotBuilt();
|
||||
query.setValues(values);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder insertInto(final OnConflict onConflict, final String table) {
|
||||
checkNotBuilt();
|
||||
query.setOnConflict(onConflict);
|
||||
|
@ -91,11 +91,11 @@ dependencies {
|
||||
compile 'com.soundcloud.android:android-crop:1.0.0@aar'
|
||||
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
|
||||
compile 'com.github.mariotaku:PickNCrop:76563fae81'
|
||||
compile 'com.diogobernardino:williamchart:1.7.0'
|
||||
googleCompile 'com.google.android.gms:play-services-maps:7.5.0'
|
||||
googleCompile 'com.google.maps.android:android-maps-utils:0.3.4'
|
||||
fdroidCompile 'org.osmdroid:osmdroid-android:4.3'
|
||||
fdroidCompile 'org.slf4j:slf4j-simple:1.7.12'
|
||||
debugCompile 'im.dino:dbinspector:3.1.0@aar'
|
||||
debugCompile 'com.facebook.stetho:stetho:1.1.1'
|
||||
debugCompile 'com.facebook.stetho:stetho-okhttp:1.1.1'
|
||||
compile project(':twidere.component.common')
|
||||
@ -104,9 +104,9 @@ dependencies {
|
||||
// googleCompile fileTree(dir: 'libs/google', include: ['*.jar'])
|
||||
}
|
||||
|
||||
task svgToPng(type: SvgDrawableTask) {
|
||||
task svgToDrawable(type: SvgDrawableTask) {
|
||||
// specify where to pick SVG from
|
||||
from = file('src/main/svg-png')
|
||||
from = file('src/main/svg/drawable')
|
||||
// specify the android res folder
|
||||
to = file('src/main/res-svg2png')
|
||||
// create qualified directories if missing
|
||||
@ -116,7 +116,9 @@ task svgToPng(type: SvgDrawableTask) {
|
||||
// let generate PNG for the following densities only
|
||||
targetedDensities = ['hdpi', 'mdpi', 'xhdpi', 'xxhdpi', 'xxxhdpi']
|
||||
// relative path of the file specifying nine patch specs
|
||||
ninePatchConfig = file('src/main/svg-png/9patch.json')
|
||||
ninePatchConfig = file('src/main/svg/drawable/9patch.json')
|
||||
// output format of the generated resources
|
||||
outputFormat = 'PNG'
|
||||
|
||||
outputType = 'drawable'
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2014 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/>.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="im.dino.dbinspector.activities.DbInspectorActivity"
|
||||
android:exported="false"
|
||||
android:label="Database Inspector"
|
||||
tools:replace="android:label">
|
||||
<intent-filter tools:node="removeAll">
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="org.mariotaku.twidere.HIDDEN_SETTINGS_ENTRY"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
@ -23,15 +23,19 @@ import android.app.Application;
|
||||
|
||||
import com.facebook.stetho.Stetho;
|
||||
import com.facebook.stetho.okhttp.StethoInterceptor;
|
||||
import com.squareup.okhttp.Interceptor;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/5/27.
|
||||
*/
|
||||
public class DebugModeUtils {
|
||||
|
||||
public static void initForHttpClient(final OkHttpClient client) {
|
||||
client.networkInterceptors().add(new StethoInterceptor());
|
||||
final List<Interceptor> interceptors = client.networkInterceptors();
|
||||
interceptors.add(new StethoInterceptor());
|
||||
}
|
||||
|
||||
public static void initForApplication(final Application application) {
|
||||
|
@ -13,6 +13,7 @@ import org.mariotaku.restfu.http.mime.FileTypedData;
|
||||
import org.mariotaku.restfu.http.mime.MultipartTypedBody;
|
||||
import org.mariotaku.twidere.BuildConfig;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
import org.mariotaku.twidere.util.TwitterAPIFactory;
|
||||
|
||||
import java.io.File;
|
||||
@ -66,6 +67,7 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> implem
|
||||
final MultipartTypedBody body = new MultipartTypedBody();
|
||||
body.add("file", new FileTypedData(tmp));
|
||||
builder.body(body);
|
||||
builder.extra(RequestType.USAGE_STATISTICS);
|
||||
final RestHttpResponse response = client.execute(builder.build());
|
||||
if (response.isSuccessful()) {
|
||||
SpiceProfilingUtil.log("server has already received file " + tmp.getName());
|
||||
|
@ -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 = 99;
|
||||
int DATABASES_VERSION = 104;
|
||||
|
||||
int MENU_GROUP_STATUS_EXTENSION = 10;
|
||||
int MENU_GROUP_COMPOSE_EXTENSION = 11;
|
||||
|
@ -72,7 +72,6 @@ import org.mariotaku.twidere.api.twitter.auth.OAuthAuthorization;
|
||||
import org.mariotaku.twidere.api.twitter.auth.OAuthEndpoint;
|
||||
import org.mariotaku.twidere.api.twitter.auth.OAuthToken;
|
||||
import org.mariotaku.twidere.api.twitter.model.User;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.fragment.support.BaseSupportDialogFragment;
|
||||
import org.mariotaku.twidere.fragment.support.SupportProgressDialogFragment;
|
||||
import org.mariotaku.twidere.graphic.EmptyDrawable;
|
||||
@ -123,7 +122,6 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
private LinearLayout mSignInSignUpContainer, mUsernamePasswordContainer;
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
private TwidereApplication mApplication;
|
||||
private SharedPreferences mPreferences;
|
||||
private ContentResolver mResolver;
|
||||
private AbstractSignInTask mTask;
|
||||
@ -308,7 +306,6 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
super.onCreate(savedInstanceState);
|
||||
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
|
||||
mResolver = getContentResolver();
|
||||
mApplication = TwidereApplication.getInstance(this);
|
||||
setContentView(R.layout.activity_sign_in);
|
||||
setSupportActionBar((Toolbar) findViewById(R.id.action_bar));
|
||||
|
||||
@ -334,15 +331,17 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
|
||||
mAPIChangeTimestamp = savedInstanceState.getLong(EXTRA_API_LAST_CHANGE);
|
||||
}
|
||||
|
||||
mUsernamePasswordContainer
|
||||
.setVisibility(mAuthType == ParcelableCredentials.AUTH_TYPE_TWIP_O_MODE ? View.GONE : View.VISIBLE);
|
||||
mSignInSignUpContainer.setOrientation(mAuthType == ParcelableCredentials.AUTH_TYPE_TWIP_O_MODE ? LinearLayout.VERTICAL
|
||||
: LinearLayout.HORIZONTAL);
|
||||
final boolean isTwipOMode = mAuthType == ParcelableCredentials.AUTH_TYPE_TWIP_O_MODE;
|
||||
mUsernamePasswordContainer.setVisibility(isTwipOMode ? View.GONE : View.VISIBLE);
|
||||
mSignInSignUpContainer.setOrientation(isTwipOMode ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
|
||||
|
||||
mEditUsername.setText(mUsername);
|
||||
mEditUsername.addTextChangedListener(this);
|
||||
mEditPassword.setText(mPassword);
|
||||
mEditPassword.addTextChangedListener(this);
|
||||
|
||||
mSignUpButton.setOnClickListener(this);
|
||||
|
||||
final Resources resources = getResources();
|
||||
final ColorStateList color = ColorStateList.valueOf(resources.getColor(R.color.material_light_green));
|
||||
ViewCompat.setBackgroundTintList(mSignInButton, color);
|
||||
|
@ -61,8 +61,14 @@ import com.squareup.otto.Bus;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.querybuilder.OnConflict;
|
||||
import org.mariotaku.querybuilder.RawItemArray;
|
||||
import org.mariotaku.querybuilder.RawSQLLang;
|
||||
import org.mariotaku.querybuilder.SQLQueryBuilder;
|
||||
import org.mariotaku.querybuilder.SetValue;
|
||||
import org.mariotaku.querybuilder.query.SQLInsertQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLSelectQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLUpdateQuery;
|
||||
import org.mariotaku.twidere.BuildConfig;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.R;
|
||||
@ -78,6 +84,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Preferences;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
@ -160,6 +167,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
case TABLE_ID_DIRECT_MESSAGES_CONVERSATION:
|
||||
case TABLE_ID_DIRECT_MESSAGES:
|
||||
case TABLE_ID_DIRECT_MESSAGES_CONVERSATIONS_ENTRIES:
|
||||
case TABLE_ID_NETWORK_USAGES:
|
||||
return 0;
|
||||
}
|
||||
int result = 0;
|
||||
@ -300,6 +308,35 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
rowId = mDatabaseWrapper.insertWithOnConflict(table, null, values,
|
||||
SQLiteDatabase.CONFLICT_IGNORE);
|
||||
}
|
||||
} else if (tableId == TABLE_ID_NETWORK_USAGES) {
|
||||
rowId = 0;
|
||||
final long timeInHours = values.getAsLong(NetworkUsages.TIME_IN_HOURS);
|
||||
final String requestNetwork = values.getAsString(NetworkUsages.REQUEST_NETWORK);
|
||||
final String requestType = values.getAsString(NetworkUsages.REQUEST_TYPE);
|
||||
final SQLInsertQuery insertOrIgnore = SQLQueryBuilder.insertInto(OnConflict.IGNORE, table)
|
||||
.columns(new String[]{NetworkUsages.TIME_IN_HOURS, NetworkUsages.REQUEST_NETWORK, NetworkUsages.REQUEST_TYPE,
|
||||
NetworkUsages.KILOBYTES_RECEIVED, NetworkUsages.KILOBYTES_SENT})
|
||||
.values("?, ?, ?, ?, ?")
|
||||
.build();
|
||||
final SQLUpdateQuery updateIncremental = SQLQueryBuilder.update(OnConflict.REPLACE, table)
|
||||
.set(
|
||||
new SetValue(NetworkUsages.KILOBYTES_RECEIVED, new RawSQLLang(NetworkUsages.KILOBYTES_RECEIVED + " + ?")),
|
||||
new SetValue(NetworkUsages.KILOBYTES_SENT, new RawSQLLang(NetworkUsages.KILOBYTES_SENT + " + ?"))
|
||||
)
|
||||
.where(Expression.and(
|
||||
Expression.equals(NetworkUsages.TIME_IN_HOURS, timeInHours),
|
||||
Expression.equalsArgs(NetworkUsages.REQUEST_NETWORK),
|
||||
Expression.equalsArgs(NetworkUsages.REQUEST_TYPE)
|
||||
))
|
||||
.build();
|
||||
mDatabaseWrapper.beginTransaction();
|
||||
mDatabaseWrapper.execSQL(insertOrIgnore.getSQL(),
|
||||
new Object[]{timeInHours, requestNetwork, requestType, 0.0, 0.0});
|
||||
mDatabaseWrapper.execSQL(updateIncremental.getSQL(),
|
||||
new Object[]{values.getAsDouble(NetworkUsages.KILOBYTES_RECEIVED),
|
||||
values.getAsDouble(NetworkUsages.KILOBYTES_SENT), requestNetwork, requestType});
|
||||
mDatabaseWrapper.setTransactionSuccessful();
|
||||
mDatabaseWrapper.endTransaction();
|
||||
} else if (shouldReplaceOnConflict(tableId)) {
|
||||
rowId = mDatabaseWrapper.insertWithOnConflict(table, null, values,
|
||||
SQLiteDatabase.CONFLICT_REPLACE);
|
||||
@ -508,6 +545,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
case TABLE_ID_DIRECT_MESSAGES_CONVERSATION:
|
||||
case TABLE_ID_DIRECT_MESSAGES:
|
||||
case TABLE_ID_DIRECT_MESSAGES_CONVERSATIONS_ENTRIES:
|
||||
case TABLE_ID_NETWORK_USAGES:
|
||||
return 0;
|
||||
}
|
||||
result = mDatabaseWrapper.update(table, values, selection, selectionArgs);
|
||||
@ -578,6 +616,11 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
throw new SecurityException("Access database " + table + " requires level PERMISSION_LEVEL_READ");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!mPermissionsManager.checkSignature(Binder.getCallingUid())) {
|
||||
throw new SecurityException("Internal database is not allowed for third-party applications");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,6 +661,11 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
||||
throw new SecurityException("Access database " + table + " requires level PERMISSION_LEVEL_WRITE");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!mPermissionsManager.checkSignature(Binder.getCallingUid())) {
|
||||
throw new SecurityException("Internal database is not allowed for third-party applications");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ 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;
|
||||
@ -60,7 +61,9 @@ public class ConnectivityStateReceiver extends BroadcastReceiver implements Cons
|
||||
+ location.getLatitude() + "," + location.getLongitude() + "," + location.getProvider());
|
||||
}
|
||||
}
|
||||
final boolean isWifi = Utils.isOnWifi(context.getApplicationContext());
|
||||
final int networkType = Utils.getActiveNetworkType(context.getApplicationContext());
|
||||
NetworkUsageUtils.setNetworkType(networkType);
|
||||
final boolean isWifi = networkType == ConnectivityManager.TYPE_WIFI;
|
||||
final boolean isCharging = SpiceProfilingUtil.isCharging(context.getApplicationContext());
|
||||
if (isWifi && isCharging) {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
|
@ -40,6 +40,7 @@ import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.api.twitter.TwitterException;
|
||||
import org.mariotaku.twidere.api.twitter.TwitterOAuth;
|
||||
import org.mariotaku.twidere.api.twitter.auth.OAuthToken;
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlPullParserFactory;
|
||||
@ -75,7 +76,7 @@ public class OAuthPasswordAuthenticator implements Constants {
|
||||
try {
|
||||
requestToken = oauth.getRequestToken(OAUTH_CALLBACK_OOB);
|
||||
} catch (final TwitterException e) {
|
||||
// if (e.isCausedByNetworkIssue()) throw new AuthenticationException(e);
|
||||
if (e.isCausedByNetworkIssue()) throw new AuthenticationException(e);
|
||||
throw new AuthenticityTokenException(e);
|
||||
}
|
||||
RestHttpResponse authorizePage = null, authorizeResult = null;
|
||||
@ -86,6 +87,7 @@ public class OAuthPasswordAuthenticator implements Constants {
|
||||
authorizePageBuilder.method(GET.METHOD);
|
||||
authorizePageBuilder.url(endpoint.construct("/oauth/authorize", Pair.create("oauth_token",
|
||||
requestToken.getOauthToken())));
|
||||
authorizePageBuilder.extra(RequestType.API);
|
||||
final RestHttpRequest authorizePageRequest = authorizePageBuilder.build();
|
||||
authorizePage = client.execute(authorizePageRequest);
|
||||
final String[] cookieHeaders = authorizePage.getHeaders("Set-Cookie");
|
||||
@ -120,6 +122,7 @@ public class OAuthPasswordAuthenticator implements Constants {
|
||||
authorizeResultBuilder.url(endpoint.construct("/oauth/authorize"));
|
||||
authorizeResultBuilder.headers(requestHeaders);
|
||||
authorizeResultBuilder.body(authorizationResultBody);
|
||||
authorizeResultBuilder.extra(RequestType.API);
|
||||
authorizeResult = client.execute(authorizeResultBuilder.build());
|
||||
final String oauthPin = readOAuthPINFromHtml(BaseTypedData.reader(authorizeResult.getBody()));
|
||||
if (isEmpty(oauthPin)) throw new WrongUserPassException();
|
||||
|
@ -29,6 +29,7 @@ import org.mariotaku.restfu.http.RestHttpRequest;
|
||||
import org.mariotaku.restfu.http.RestHttpResponse;
|
||||
import org.mariotaku.restfu.http.mime.TypedData;
|
||||
import org.mariotaku.twidere.activity.support.ThemedImagePickerActivity;
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -46,6 +47,7 @@ public class RestFuNetworkStreamDownloader extends ThemedImagePickerActivity.Net
|
||||
final RestHttpRequest.Builder builder = new RestHttpRequest.Builder();
|
||||
builder.method(GET.METHOD);
|
||||
builder.url(uri.toString());
|
||||
builder.extra(RequestType.MEDIA);
|
||||
final RestHttpResponse response = client.execute(builder.build());
|
||||
if (response.isSuccessful()) {
|
||||
final TypedData body = response.getBody();
|
||||
|
@ -2,6 +2,7 @@ package org.mariotaku.twidere.util;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
public class SQLiteDatabaseWrapper {
|
||||
@ -47,6 +48,18 @@ public class SQLiteDatabaseWrapper {
|
||||
return mDatabase.insertWithOnConflict(table, nullColumnHack, initialValues, conflictAlgorithm);
|
||||
}
|
||||
|
||||
public void execSQL(String sql) throws SQLException {
|
||||
tryCreateDatabase();
|
||||
if (mDatabase == null) return;
|
||||
mDatabase.execSQL(sql);
|
||||
}
|
||||
|
||||
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
|
||||
tryCreateDatabase();
|
||||
if (mDatabase == null) return;
|
||||
mDatabase.execSQL(sql, bindArgs);
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
if (mLazyLoadCallback != null) return true;
|
||||
return mDatabase != null;
|
||||
|
@ -44,6 +44,7 @@ import org.mariotaku.twidere.api.twitter.util.TwitterConverter;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.model.ConsumerKeyType;
|
||||
import org.mariotaku.twidere.model.ParcelableCredentials;
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
import org.mariotaku.twidere.util.net.OkHttpRestClient;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
@ -119,7 +120,7 @@ public class TwitterAPIFactory implements TwidereConstants {
|
||||
client.setProxy(getProxy(prefs));
|
||||
}
|
||||
Internal.instance.setNetwork(client, TwidereApplication.getInstance(context).getNetwork());
|
||||
return new OkHttpRestClient(client);
|
||||
return new OkHttpRestClient(context, client);
|
||||
}
|
||||
|
||||
|
||||
@ -373,7 +374,7 @@ public class TwitterAPIFactory implements TwidereConstants {
|
||||
headers.add(Pair.create("Authorization", authorization.getHeader(endpoint, info)));
|
||||
}
|
||||
headers.add(Pair.create("User-Agent", userAgent));
|
||||
return new RestHttpRequest(restMethod, url, headers, info.getBody(), null);
|
||||
return new RestHttpRequest(restMethod, url, headers, info.getBody(), RequestType.API);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +214,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters.Users;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Notifications;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Permissions;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Preferences;
|
||||
@ -319,6 +320,8 @@ public final class Utils implements Constants {
|
||||
TABLE_ID_SAVED_SEARCHES);
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, SearchHistory.CONTENT_PATH,
|
||||
TABLE_ID_SEARCH_HISTORY);
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, NetworkUsages.CONTENT_PATH,
|
||||
TABLE_ID_NETWORK_USAGES);
|
||||
|
||||
CONTENT_PROVIDER_URI_MATCHER.addURI(TwidereDataStore.AUTHORITY, Notifications.CONTENT_PATH,
|
||||
VIRTUAL_TABLE_ID_NOTIFICATIONS);
|
||||
@ -2184,6 +2187,8 @@ public final class Utils implements Constants {
|
||||
return SavedSearches.TABLE_NAME;
|
||||
case TABLE_ID_SEARCH_HISTORY:
|
||||
return SearchHistory.TABLE_NAME;
|
||||
case TABLE_ID_NETWORK_USAGES:
|
||||
return NetworkUsages.TABLE_NAME;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -2518,6 +2523,13 @@ public final class Utils implements Constants {
|
||||
&& networkInfo.isConnected();
|
||||
}
|
||||
|
||||
public static int getActiveNetworkType(final Context context) {
|
||||
if (context == null) return -1;
|
||||
final ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
final NetworkInfo networkInfo = conn.getActiveNetworkInfo();
|
||||
return networkInfo != null && networkInfo.isConnected() ? networkInfo.getType() : -1;
|
||||
}
|
||||
|
||||
public static boolean isRedirected(final int code) {
|
||||
return code == 301 || code == 302 || code == 307;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import android.text.TextUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.mariotaku.querybuilder.Columns;
|
||||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
import org.mariotaku.querybuilder.Constraint;
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.querybuilder.NewColumn;
|
||||
import org.mariotaku.querybuilder.OnConflict;
|
||||
@ -48,38 +49,23 @@ import static org.mariotaku.querybuilder.SQLQueryBuilder.insertInto;
|
||||
import static org.mariotaku.querybuilder.SQLQueryBuilder.select;
|
||||
|
||||
public final class DatabaseUpgradeHelper {
|
||||
public static void safeUpgrade(final SQLiteDatabase db, final String table, final String[] newColNames,
|
||||
final String[] newColTypes, final boolean dropDirectly, final boolean strictMode,
|
||||
final Map<String, String> colAliases) {
|
||||
safeUpgrade(db, table, newColNames, newColTypes, dropDirectly, strictMode, colAliases, OnConflict.REPLACE);
|
||||
}
|
||||
|
||||
public static void safeUpgrade(final SQLiteDatabase db, final String table, final String[] newColNames,
|
||||
final String[] newColTypes, final boolean dropDirectly, final boolean strictMode,
|
||||
final Map<String, String> colAliases, final OnConflict onConflict) {
|
||||
|
||||
final String[] newColTypes, final boolean dropDirectly,
|
||||
final Map<String, String> colAliases, final OnConflict onConflict,
|
||||
final Constraint... constraints) {
|
||||
if (newColNames == null || newColTypes == null || newColNames.length != newColTypes.length)
|
||||
throw new IllegalArgumentException("Invalid parameters for upgrading table " + table
|
||||
+ ", length of columns and types not match.");
|
||||
|
||||
// First, create the table if not exists.
|
||||
final NewColumn[] newCols = NewColumn.createNewColumns(newColNames, newColTypes);
|
||||
final String createQuery = createTable(true, table).columns(newCols).buildSQL();
|
||||
final String createQuery = createTable(true, table).columns(newCols).constraint(constraints).buildSQL();
|
||||
db.execSQL(createQuery);
|
||||
|
||||
// We need to get all data from old table.
|
||||
final String[] oldCols = getColumnNames(db, table);
|
||||
if (strictMode) {
|
||||
final String oldCreate = getCreateSQL(db, table);
|
||||
final Map<String, String> map = getTypeMapByCreateQuery(oldCreate);
|
||||
boolean different = false;
|
||||
for (final NewColumn newCol : newCols) {
|
||||
if (!newCol.getType().equalsIgnoreCase(map.get(newCol.getName()))) {
|
||||
different = true;
|
||||
}
|
||||
}
|
||||
if (!different) return;
|
||||
} else if (oldCols == null || TwidereArrayUtils.contentMatch(newColNames, oldCols)) return;
|
||||
if (oldCols == null || TwidereArrayUtils.contentMatch(newColNames, oldCols)) return;
|
||||
if (dropDirectly) {
|
||||
db.beginTransaction();
|
||||
db.execSQL(dropTable(true, table).getSQL());
|
||||
@ -104,8 +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) {
|
||||
safeUpgrade(db, table, newColNames, newColTypes, dropDirectly, true, colAliases, OnConflict.REPLACE);
|
||||
final String[] newColTypes, final boolean dropDirectly, final Map<String, String> colAliases, final Constraint... constraints) {
|
||||
safeUpgrade(db, table, newColNames, newColTypes, dropDirectly, colAliases, OnConflict.REPLACE, constraints);
|
||||
}
|
||||
|
||||
private static String createInsertDataQuery(final String table, final String tempTable, final String[] newCols,
|
||||
|
@ -28,6 +28,7 @@ import android.os.Build;
|
||||
|
||||
import org.mariotaku.querybuilder.Columns;
|
||||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
import org.mariotaku.querybuilder.Constraint;
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
import org.mariotaku.querybuilder.NewColumn;
|
||||
import org.mariotaku.querybuilder.OnConflict;
|
||||
@ -51,6 +52,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.SearchHistory;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
|
||||
@ -96,6 +98,7 @@ 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()));
|
||||
|
||||
createViews(db);
|
||||
createTriggers(db);
|
||||
@ -105,6 +108,10 @@ 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 void createIndices(SQLiteDatabase db) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
|
||||
db.execSQL(createIndex("statuses_index", Statuses.TABLE_NAME, new String[]{Statuses.ACCOUNT_ID}, true));
|
||||
@ -248,6 +255,8 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
||||
safeUpgrade(db, Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, false, null);
|
||||
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());
|
||||
db.beginTransaction();
|
||||
createViews(db);
|
||||
createTriggers(db);
|
||||
@ -257,9 +266,10 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
||||
}
|
||||
|
||||
private static String createTable(final String tableName, final String[] columns, final String[] types,
|
||||
final boolean createIfNotExists) {
|
||||
final boolean createIfNotExists, final Constraint... constraints) {
|
||||
final SQLCreateTableQuery.Builder qb = SQLQueryBuilder.createTable(createIfNotExists, tableName);
|
||||
qb.columns(NewColumn.createNewColumns(columns, types));
|
||||
qb.constraint(constraints);
|
||||
return qb.buildSQL();
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ import org.mariotaku.twidere.constant.SharedPreferenceConstants;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableCredentials;
|
||||
import org.mariotaku.twidere.model.ParcelableMedia;
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
import org.mariotaku.twidere.util.MediaPreviewUtils;
|
||||
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify;
|
||||
@ -186,7 +187,12 @@ public class TwidereImageDownloader extends BaseImageDownloader implements Const
|
||||
} else {
|
||||
requestUri = modifiedUri.toString();
|
||||
}
|
||||
final RestHttpResponse resp = mClient.execute(new RestHttpRequest.Builder().method(method).url(requestUri).headers(additionalHeaders).build());
|
||||
final RestHttpRequest.Builder builder = new RestHttpRequest.Builder();
|
||||
builder.method(method);
|
||||
builder.url(requestUri);
|
||||
builder.headers(additionalHeaders);
|
||||
builder.extra(RequestType.MEDIA);
|
||||
final RestHttpResponse resp = mClient.execute(builder.build());
|
||||
final TypedData body = resp.getBody();
|
||||
return new ContentLengthInputStream(body.stream(), (int) body.length());
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.net;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
|
||||
import com.squareup.okhttp.Interceptor;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.RequestBody;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.ResponseBody;
|
||||
|
||||
import org.mariotaku.twidere.model.RequestType;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/6/24.
|
||||
*/
|
||||
public class NetworkUsageUtils {
|
||||
public static void initForHttpClient(Context context, OkHttpClient client) {
|
||||
client.networkInterceptors().add(new NetworkUsageInterceptor(context));
|
||||
}
|
||||
|
||||
private static int sNetworkType;
|
||||
|
||||
public static void setNetworkType(int networkType) {
|
||||
NetworkUsageUtils.sNetworkType = networkType;
|
||||
}
|
||||
|
||||
private static class NetworkUsageInterceptor implements Interceptor {
|
||||
private final Context context;
|
||||
|
||||
public NetworkUsageInterceptor(Context context) {
|
||||
this.context = context;
|
||||
setNetworkType(Utils.getActiveNetworkType(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
final Request request = chain.request();
|
||||
final Object tag = request.tag();
|
||||
if (!(tag instanceof RequestType)) return chain.proceed(request);
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(NetworkUsages.TIME_IN_HOURS, System.currentTimeMillis() / 1000 / 60 / 60);
|
||||
values.put(NetworkUsages.KILOBYTES_SENT, getBodyLength(request.body()) / 1024.0);
|
||||
values.put(NetworkUsages.REQUEST_TYPE, ((RequestType) tag).getName());
|
||||
values.put(NetworkUsages.REQUEST_NETWORK, sNetworkType);
|
||||
final Response response = chain.proceed(request);
|
||||
values.put(NetworkUsages.KILOBYTES_RECEIVED, getBodyLength(response.body()) / 1024.0);
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
cr.insert(NetworkUsages.CONTENT_URI, values);
|
||||
return response;
|
||||
}
|
||||
|
||||
private long getBodyLength(RequestBody body) throws IOException {
|
||||
if (body == null) return 0;
|
||||
final long length = body.contentLength();
|
||||
return length > 0 ? length : 0;
|
||||
}
|
||||
|
||||
private long getBodyLength(ResponseBody body) throws IOException {
|
||||
if (body == null) return 0;
|
||||
final long length = body.contentLength();
|
||||
return length > 0 ? length : 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
|
||||
package org.mariotaku.twidere.util.net;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
@ -59,12 +60,9 @@ public class OkHttpRestClient implements RestHttpClient {
|
||||
|
||||
private final OkHttpClient client;
|
||||
|
||||
public OkHttpRestClient() {
|
||||
this(new OkHttpClient());
|
||||
}
|
||||
|
||||
public OkHttpRestClient(OkHttpClient client) {
|
||||
public OkHttpRestClient(Context context, OkHttpClient client) {
|
||||
this.client = client;
|
||||
NetworkUsageUtils.initForHttpClient(context, client);
|
||||
DebugModeUtils.initForHttpClient(client);
|
||||
}
|
||||
|
||||
@ -85,6 +83,7 @@ public class OkHttpRestClient implements RestHttpClient {
|
||||
builder.addHeader(header.first, header.second);
|
||||
}
|
||||
}
|
||||
builder.tag(restHttpRequest.getExtra());
|
||||
return client.newCall(builder.build());
|
||||
}
|
||||
|
||||
@ -132,6 +131,11 @@ public class OkHttpRestClient implements RestHttpClient {
|
||||
body.writeTo(sink.outputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long contentLength() throws IOException {
|
||||
return body.length();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RequestBody wrap(@Nullable TypedData body) {
|
||||
if (body == null) return null;
|
||||
|
@ -85,7 +85,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="48dp"
|
||||
android:onClick="onClick"
|
||||
android:text="@string/register"/>
|
||||
|
||||
<Button
|
||||
|
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 300 B After Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 386 B |
Before Width: | Height: | Size: 874 B After Width: | Height: | Size: 874 B |
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 232 B |
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 404 B |
Before Width: | Height: | Size: 568 B After Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 529 B After Width: | Height: | Size: 529 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 327 B |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 398 B After Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |