added workaround for blackberry devices when setting hotkey.

added quote user to reply dialog for quoted tweet
trying to make mock user-agent work for some consumer keys.
This commit is contained in:
Mariotaku Lee 2015-04-20 23:06:39 +08:00
parent d7b934a3e0
commit 738fc2468b
26 changed files with 641 additions and 161 deletions

View File

@ -0,0 +1,39 @@
/*
* 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;
import android.support.annotation.NonNull;
/**
* Created by mariotaku on 15/4/20.
*/
public enum ConsumerKeyType {
TWITTER_FOR_ANDROID, TWITTER_FOR_IPHONE, TWITTER_FOR_IPAD, TWITTER_FOR_MAC,
TWITTER_FOR_WINDOWS_PHONE, TWITTER_FOR_GOOGLE_TV, UNKNOWN;
@NonNull
public static ConsumerKeyType parse(String type) {
try {
return ConsumerKeyType.valueOf(type);
} catch (Exception e) {
return UNKNOWN;
}
}
}

View File

@ -495,10 +495,12 @@ public class ParcelableMedia implements Parcelable, JSONParcelable, SimpleValueS
}
public static final Parcelable.Creator<Variant> CREATOR = new Parcelable.Creator<Variant>() {
@Override
public Variant createFromParcel(Parcel source) {
return new Variant(source);
}
@Override
public Variant[] newArray(int size) {
return new Variant[size];
}
@ -526,10 +528,12 @@ public class ParcelableMedia implements Parcelable, JSONParcelable, SimpleValueS
}
public static final Parcelable.Creator<VideoInfo> CREATOR = new Parcelable.Creator<VideoInfo>() {
@Override
public VideoInfo createFromParcel(Parcel source) {
return new VideoInfo(source);
}
@Override
public VideoInfo[] newArray(int size) {
return new VideoInfo[size];
}

View File

@ -23,6 +23,7 @@ import android.content.Context;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.common.R;
import org.mariotaku.twidere.model.ConsumerKeyType;
import java.nio.charset.Charset;
import java.util.zip.CRC32;
@ -120,6 +121,43 @@ public class TwitterContentUtils {
return false;
}
public static String getOfficialKeyName(final Context context, final String consumerKey,
final String consumerSecret) {
if (context == null || consumerKey == null || consumerSecret == null) return null;
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_secret_crc32);
final String[] keyNames = context.getResources().getStringArray(R.array.names_official_consumer_secret);
final CRC32 crc32 = new CRC32();
final byte[] consumerSecretBytes = consumerSecret.getBytes(Charset.forName("UTF-8"));
crc32.update(consumerSecretBytes, 0, consumerSecretBytes.length);
final long value = crc32.getValue();
crc32.reset();
for (int i = 0, j = keySecrets.length; i < j; i++) {
if (Long.parseLong(keySecrets[i], 16) == value) return keyNames[i];
}
return null;
}
@NonNull
public static ConsumerKeyType getOfficialKeyType(final Context context, final String consumerKey,
final String consumerSecret) {
if (context == null || consumerKey == null || consumerSecret == null) {
return ConsumerKeyType.UNKNOWN;
}
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_secret_crc32);
final String[] keyNames = context.getResources().getStringArray(R.array.types_official_consumer_secret);
final CRC32 crc32 = new CRC32();
final byte[] consumerSecretBytes = consumerSecret.getBytes(Charset.forName("UTF-8"));
crc32.update(consumerSecretBytes, 0, consumerSecretBytes.length);
final long value = crc32.getValue();
crc32.reset();
for (int i = 0, j = keySecrets.length; i < j; i++) {
if (Long.parseLong(keySecrets[i], 16) == value) {
return ConsumerKeyType.parse(keyNames[i]);
}
}
return ConsumerKeyType.UNKNOWN;
}
private static void parseEntities(final HtmlBuilder builder, final EntitySupport entities) {
// Format media.
final MediaEntity[] mediaEntities = entities.getMediaEntities();

View File

@ -34,7 +34,7 @@
<!--Twitter for Google TV-->
<item>56d8f9ff</item>
</string-array>
<string-array name="names_official_consumer_secret_crc32">
<string-array name="names_official_consumer_secret">
<!--Twitter for Android-->
<item>Twitter for Android</item>
<!--Twitter for iPhone-->
@ -48,4 +48,18 @@
<!--Twitter for Google TV-->
<item>Twitter for Google TV</item>
</string-array>
<string-array name="types_official_consumer_secret">
<!--Twitter for Android-->
<item>TWITTER_FOR_ANDROID</item>
<!--Twitter for iPhone-->
<item>TWITTER_FOR_IPHONE</item>
<!--Twitter for iPad-->
<item>TWITTER_FOR_IPAD</item>
<!--Twitter for Mac-->
<item>TWITTER_FOR_MAC</item>
<!--Twitter for Windows Phone-->
<item>TWITTER_FOR_WINDOWS_PHONE</item>
<!--Twitter for Google TV-->
<item>TWITTER_FOR_GOOGLE_TV</item>
</string-array>
</resources>

View File

@ -584,6 +584,9 @@
android:name="com.android.systemui.action_assist_icon"
android:resource="@drawable/ic_assist_twidere"/>
</activity>
<activity
android:name=".activity.KeyboardShortcutPreferenceCompatActivity"
android:theme="@style/Theme.Blank.Dialog"/>
<activity
android:name=".activity.TestActivity"
android:enabled="false"

View File

@ -31,7 +31,7 @@ public class SpiceService extends Service {
public void onCreate() {
super.onCreate();
SpiceProfilingUtil.log(this, "onCreate");
SpiceProfilingUtil.log("onCreate");
mAlarmManager = (AlarmManager) getSystemService(Service.ALARM_SERVICE);
IntentFilter screenFilter = new IntentFilter();
@ -58,10 +58,10 @@ public class SpiceService extends Service {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_ON)) {
SpiceProfilingUtil.profile(context, SpiceProfilingUtil.FILE_NAME_SCREEN, "SCREEN ON" + "," + NetworkStateUtil.getConnectedType(context));
SpiceProfilingUtil.log(context, "SCREEN ON" + "," + NetworkStateUtil.getConnectedType(context));
SpiceProfilingUtil.log("SCREEN ON" + "," + NetworkStateUtil.getConnectedType(context));
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
SpiceProfilingUtil.profile(context, SpiceProfilingUtil.FILE_NAME_SCREEN, "SCREEN OFF" + "," + NetworkStateUtil.getConnectedType(context));
SpiceProfilingUtil.log(context, "SCREEN OFF" + "," + NetworkStateUtil.getConnectedType(context));
SpiceProfilingUtil.log("SCREEN OFF" + "," + NetworkStateUtil.getConnectedType(context));
}
}

View File

@ -46,7 +46,7 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> {
final File tmp_dir = new File(app_root + "/spice");
if (!tmp_dir.exists()) {
if (!tmp_dir.mkdirs()) {
SpiceProfilingUtil.log(context, "cannot create folder spice, do nothing.");
SpiceProfilingUtil.log("cannot create folder spice, do nothing.");
return;
}
}
@ -58,12 +58,12 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> {
final String url = PROFILE_SERVER_URL;
final HttpParameter[] parameters = {new HttpParameter("file", tmp)};
client.post(url, url, parameters);
SpiceProfilingUtil.log(context, "server has already received file " + tmp.getName());
SpiceProfilingUtil.log("server has already received file " + tmp.getName());
tmp.delete();
} catch (Exception e) {
if (Utils.isDebugBuild()) {
Log.w(LOGTAG, e);
SpiceProfilingUtil.log(context, "server does not receive file " + tmp.getName());
SpiceProfilingUtil.log("server does not receive file " + tmp.getName());
}
putBackProfile(context, tmp, file);
}
@ -80,7 +80,7 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> {
final long lastUpload = prefs.getLong(LAST_UPLOAD_DATE, System.currentTimeMillis());
final double deltaDays = (System.currentTimeMillis() - lastUpload) / (MILLSECS_HALF_DAY * 2);
if (deltaDays < 1) {
SpiceProfilingUtil.log(context, "Last uploaded was conducted in 1 day ago.");
SpiceProfilingUtil.log("Last uploaded was conducted in 1 day ago.");
return null;
}
}
@ -99,7 +99,7 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> {
continue;
}
final String url = PROFILE_SERVER_URL;
SpiceProfilingUtil.log(context, url);
SpiceProfilingUtil.log(url);
uploadMultipart(file);
}
return false;
@ -121,15 +121,15 @@ public class SpiceAsyUploadTask extends AsyncTask<Object, Object, Object> {
}
if (success && tmp.renameTo(profile) && tmp.delete()) {
SpiceProfilingUtil.log(context, "put profile back success");
SpiceProfilingUtil.log("put profile back success");
} else {
SpiceProfilingUtil.log(context, "put profile back failed");
SpiceProfilingUtil.log("put profile back failed");
}
} else {
if (tmp.renameTo(profile)) {
SpiceProfilingUtil.log(context, "put profile back success");
SpiceProfilingUtil.log("put profile back success");
} else {
SpiceProfilingUtil.log(context, "put profile back failed");
SpiceProfilingUtil.log("put profile back failed");
}
}
}

View File

@ -43,11 +43,11 @@ public class SpiceProfilingUtil {
|| plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
}
public static boolean log(final Context context, final String msg) {
if (Utils.isDebuggable(context)) {
public static boolean log(final String msg) {
if (Utils.isDebugBuild()) {
final StackTraceElement ste = new Throwable().fillInStackTrace().getStackTrace()[1];
final String fullname = ste.getClassName();
final String name = fullname.substring(fullname.lastIndexOf('.'));
final String fullName = ste.getClassName();
final String name = fullName.substring(fullName.lastIndexOf('.'));
final String tag = name + "." + ste.getMethodName();
Log.d(tag, msg);
return true;

View File

@ -30,7 +30,7 @@ public class ProfilingUtil {
}
public static boolean log(final Context context, final String msg) {
if (Utils.isDebuggable(context)) {
if (Utils.isDebugBuild()) {
final StackTraceElement ste = new Throwable().fillInStackTrace().getStackTrace()[1];
final String fullname = ste.getClassName();
final String name = fullname.substring(fullname.lastIndexOf('.'));

View File

@ -38,6 +38,11 @@ public abstract class BaseThemedActivity extends Activity implements IThemedActi
private String mCurrentThemeFontFamily;
private String mCurrentThemeBackgroundOption;
@Override
public String getCurrentThemeBackgroundOption() {
return mCurrentThemeBackgroundOption;
}
@Override
public int getCurrentThemeBackgroundAlpha() {
return mCurrentThemeBackgroundAlpha;

View File

@ -0,0 +1,150 @@
/*
* 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.activity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutSpec;
import org.mariotaku.twidere.util.ThemeUtils;
/**
* Created by mariotaku on 15/4/20.
*/
public class KeyboardShortcutPreferenceCompatActivity extends BaseThemedActivity implements Constants, OnClickListener {
public static final String EXTRA_CONTEXT_TAG = "context_tag";
public static final String EXTRA_KEY_ACTION = "key_action";
private KeyboardShortcutsHandler mKeyboardShortcutHandler;
private TextView mKeysLabel, mConflictLabel;
private KeyboardShortcutSpec mKeySpec;
private Button mButtonPositive, mButtonNegative, mButtonNeutral;
@Override
public String getThemeBackgroundOption() {
return VALUE_THEME_BACKGROUND_DEFAULT;
}
@Override
public int getThemeColor() {
return ThemeUtils.getThemeColor(this);
}
@Override
public int getThemeResourceId() {
return ThemeUtils.getDialogThemeResource(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mKeyboardShortcutHandler = TwidereApplication.getInstance(this).getKeyboardShortcutsHandler();
setContentView(R.layout.activity_keyboard_shortcut_input);
setTitle(KeyboardShortcutsHandler.getActionLabel(this, getKeyAction()));
mButtonPositive.setOnClickListener(this);
mButtonNegative.setOnClickListener(this);
mButtonNeutral.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_positive: {
if (mKeySpec == null) return;
mKeyboardShortcutHandler.register(mKeySpec, getKeyAction());
finish();
break;
}
case R.id.button_neutral: {
mKeyboardShortcutHandler.unregister(getKeyAction());
finish();
break;
}
case R.id.button_negative: {
finish();
break;
}
}
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
final String keyAction = getKeyAction();
if (keyAction == null) return false;
final KeyboardShortcutSpec spec = KeyboardShortcutsHandler.getKeyboardShortcutSpec(getContextTag(), keyCode, event);
if (spec == null || !spec.isValid()) {
return super.onKeyUp(keyCode, event);
}
mKeySpec = spec;
mKeysLabel.setText(spec.toKeyString());
final String oldAction = mKeyboardShortcutHandler.findAction(spec);
final KeyboardShortcutSpec copyOfSpec = spec.copy();
copyOfSpec.setContextTag(null);
final String oldGeneralAction = mKeyboardShortcutHandler.findAction(copyOfSpec);
if (!TextUtils.isEmpty(oldAction) && !keyAction.equals(oldAction)) {
// Conflicts with keys in same context tag
mConflictLabel.setVisibility(View.VISIBLE);
final String label = KeyboardShortcutsHandler.getActionLabel(this, oldAction);
mConflictLabel.setText(getString(R.string.conflicts_with_name, label));
mButtonPositive.setText((R.string.overwrite));
} else if (!TextUtils.isEmpty(oldGeneralAction) && !keyAction.equals(oldGeneralAction)) {
// Conflicts with keys in root context
mConflictLabel.setVisibility(View.VISIBLE);
final String label = KeyboardShortcutsHandler.getActionLabel(this, oldGeneralAction);
mConflictLabel.setText(getString(R.string.conflicts_with_name, label));
mButtonPositive.setText((R.string.overwrite));
} else {
mConflictLabel.setVisibility(View.GONE);
mButtonPositive.setText((android.R.string.ok));
}
return true;
}
@Override
public void onContentChanged() {
super.onContentChanged();
mKeysLabel = (TextView) findViewById(R.id.keys_label);
mConflictLabel = (TextView) findViewById(R.id.conflict_label);
mButtonPositive = (Button) findViewById(R.id.button_positive);
mButtonNegative = (Button) findViewById(R.id.button_negative);
mButtonNeutral = (Button) findViewById(R.id.button_neutral);
}
private String getContextTag() {
return getIntent().getStringExtra(EXTRA_CONTEXT_TAG);
}
private String getKeyAction() {
return getIntent().getStringExtra(EXTRA_KEY_ACTION);
}
}

View File

@ -240,11 +240,7 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity implements
TWITTER_CONSUMER_SECRET_3);
cb.setHostAddressResolverFactory(new TwidereHostResolverFactory(mApplication));
cb.setHttpClientFactory(new OkHttpClientFactory(mApplication));
if (TwitterContentUtils.isOfficialKey(mActivity, consumerKey, consumerSecret)) {
Utils.setMockOfficialUserAgent(mActivity, cb);
} else {
Utils.setUserAgent(mActivity, cb);
}
Utils.setClientUserAgent(mActivity, consumerKey, consumerSecret, cb);
cb.setRestBaseURL(DEFAULT_REST_BASE_URL);
cb.setOAuthBaseURL(DEFAULT_OAUTH_BASE_URL);
cb.setSigningRestBaseURL(DEFAULT_SIGNING_REST_BASE_URL);

View File

@ -914,6 +914,9 @@ public class ComposeActivity extends ThemedFragmentActivity implements TextWatch
if (status == null || status.id <= 0) return false;
final String myScreenName = Utils.getAccountScreenName(this, status.account_id);
if (TextUtils.isEmpty(myScreenName)) return false;
if (!TextUtils.isEmpty(status.quoted_by_user_name)) {
mEditText.append("@" + status.quoted_by_user_name + " ");
}
mEditText.append("@" + status.user_screen_name + " ");
final int selectionStart = mEditText.length();
if (!TextUtils.isEmpty(status.retweeted_by_screen_name)) {

View File

@ -44,6 +44,7 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.KeyEvent;
@ -279,6 +280,19 @@ public class HomeActivity extends BaseActionBarActivity implements OnClickListen
@Override
public boolean handleKeyboardShortcutSingle(int keyCode, @NonNull KeyEvent event) {
if (handleFragmentKeyboardShortcutSingle(keyCode, event)) return true;
final String action = mKeyboardShortcutsHandler.getKeyAction("home", keyCode, event);
if (action != null) {
switch (action) {
case "home.accounts_dashboard": {
if (mSlidingMenu.isMenuShowing()) {
mSlidingMenu.showContent(true);
} else {
mSlidingMenu.showMenu(true);
}
return true;
}
}
}
return mKeyboardShortcutsHandler.handleKey(this, null, keyCode, event);
}
@ -645,7 +659,7 @@ public class HomeActivity extends BaseActionBarActivity implements OnClickListen
public long[] getActivatedAccountIds() {
final Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.left_drawer);
if (fragment instanceof AccountsDashboardFragment) {
((AccountsDashboardFragment) fragment).getActivatedAccountIds();
return ((AccountsDashboardFragment) fragment).getActivatedAccountIds();
}
return Utils.getActivatedAccountIds(this);
}

View File

@ -67,7 +67,6 @@ import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.AuthenticityTokenEx
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.WrongUserPassException;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.ViewUtils;
import org.mariotaku.twidere.util.net.OkHttpClientFactory;
@ -369,19 +368,13 @@ public class SignInActivity extends BaseActionBarActivity implements TwitterCons
final boolean enable_proxy = mPreferences.getBoolean(KEY_ENABLE_PROXY, false);
cb.setHostAddressResolverFactory(new TwidereHostResolverFactory(mApplication));
cb.setHttpClientFactory(new OkHttpClientFactory(mApplication));
if (TwitterContentUtils.isOfficialKey(this, mConsumerKey, mConsumerSecret)) {
Utils.setMockOfficialUserAgent(this, cb);
} else {
Utils.setUserAgent(this, cb);
}
Utils.setClientUserAgent(this, mConsumerKey, mConsumerSecret, cb);
final String apiUrlFormat = TextUtils.isEmpty(mAPIUrlFormat) ? DEFAULT_TWITTER_API_URL_FORMAT : mAPIUrlFormat;
final String versionSuffix = mNoVersionSuffix ? null : "/1.1/";
cb.setRestBaseURL(Utils.getApiUrl(apiUrlFormat, "api", versionSuffix));
cb.setOAuthBaseURL(Utils.getApiUrl(apiUrlFormat, "api", "/oauth/"));
cb.setUploadBaseURL(Utils.getApiUrl(apiUrlFormat, "upload", versionSuffix));
cb.setOAuthAuthorizationURL(Utils.getApiUrl(apiUrlFormat, null, "/oauth/authorize"));
final String userAgent = TwidereApplication.getInstance(this).getDefaultUserAgent();
cb.setHttpUserAgent(userAgent);
if (!mSameOAuthSigningUrl) {
cb.setSigningRestBaseURL(DEFAULT_SIGNING_REST_BASE_URL);
cb.setSigningOAuthBaseURL(DEFAULT_SIGNING_OAUTH_BASE_URL);

View File

@ -28,10 +28,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnKeyListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Build;
import android.os.Bundle;
import android.preference.DialogPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.support.annotation.NonNull;
@ -46,6 +49,7 @@ import android.view.View;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.KeyboardShortcutPreferenceCompatActivity;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutSpec;
@ -57,18 +61,6 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
private KeyboardShortcutsHandler mKeyboardShortcutHandler;
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_RESET: {
final DialogFragment f = new ResetKeyboardShortcutConfirmDialogFragment();
f.show(getFragmentManager().beginTransaction(), "reset_keyboard_shortcut_confirm");
return true;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -92,11 +84,25 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
inflater.inflate(R.menu.menu_keyboard_shortcuts, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_RESET: {
final DialogFragment f = new ResetKeyboardShortcutConfirmDialogFragment();
f.show(getFragmentManager().beginTransaction(), "reset_keyboard_shortcut_confirm");
return true;
}
}
return super.onOptionsItemSelected(item);
}
private void addPreferences() {
final PreferenceCategory general = makeAndAddCategory(getString(R.string.general));
general.addPreference(makePreferences(null, "compose"));
general.addPreference(makePreferences(null, "search"));
general.addPreference(makePreferences(null, "message"));
final PreferenceCategory home = makeAndAddCategory(getString(R.string.home));
home.addPreference(makePreferences("home", "home.accounts_dashboard"));
final PreferenceCategory navigation = makeAndAddCategory(getString(R.string.navigation));
navigation.addPreference(makePreferences("navigation", "navigation.next"));
navigation.addPreference(makePreferences("navigation", "navigation.previous"));
@ -117,13 +123,17 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
return category;
}
private KeyboardShortcutPreferences makePreferences(String contextTag, String action) {
private Preference makePreferences(String contextTag, String action) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
final Context context = preferenceScreen.getContext();
return new KeyboardShortcutPreferences(context, mKeyboardShortcutHandler, contextTag, action);
final KeyboardShortcutsHandler shortcutHandler = mKeyboardShortcutHandler;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return new KeyboardShortcutPreferenceCompat(context, shortcutHandler, contextTag, action);
}
return new KeyboardShortcutPreference(context, shortcutHandler, contextTag, action);
}
private static class KeyboardShortcutPreferences extends DialogPreference implements OnKeyListener {
private static class KeyboardShortcutPreference extends DialogPreference implements OnKeyListener {
private final KeyboardShortcutsHandler mKeyboardShortcutHandler;
private final String mContextTag, mAction;
@ -131,8 +141,8 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
private TextView mKeysLabel, mConflictLabel;
private KeyboardShortcutSpec mKeySpec;
public KeyboardShortcutPreferences(final Context context, final KeyboardShortcutsHandler handler,
@Nullable final String contextTag, @NonNull final String action) {
public KeyboardShortcutPreference(final Context context, final KeyboardShortcutsHandler handler,
@Nullable final String contextTag, @NonNull final String action) {
//noinspection ConstantConditions
super(context, null);
mKeyboardShortcutHandler = handler;
@ -151,61 +161,12 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
updateSummary();
}
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
mKeyboardShortcutHandler.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
}
@Override
protected void onPrepareForRemoval() {
mKeyboardShortcutHandler.unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
super.onPrepareForRemoval();
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
if (mKeySpec == null) return;
mKeyboardShortcutHandler.register(mKeySpec, mAction);
break;
}
case DialogInterface.BUTTON_NEUTRAL: {
mKeyboardShortcutHandler.unregister(mAction);
break;
}
}
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
builder.setPositiveButton(getContext().getString(android.R.string.ok), this);
builder.setNegativeButton(getContext().getString(android.R.string.cancel), this);
builder.setNeutralButton(getContext().getString(R.string.clear), this);
}
@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
final Dialog dialog = getDialog();
dialog.setOnKeyListener(this);
mKeysLabel = (TextView) dialog.findViewById(R.id.keys_label);
mConflictLabel = (TextView) dialog.findViewById(R.id.conflict_label);
mConflictLabel.setVisibility(View.GONE);
}
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_UP) return false;
if (event.hasNoModifiers() && keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
mKeyboardShortcutHandler.unregister(mAction);
return true;
}
final KeyboardShortcutSpec spec = KeyboardShortcutsHandler.getKeyboardShortcutSpec(mContextTag, keyCode, event);
if (spec == null || !spec.isValid()) {
Log.d(LOGTAG, String.format("Invalid key %s", spec));
Log.d(LOGTAG, String.format("Invalid key %s", event), new Exception());
return false;
}
mKeySpec = spec;
@ -228,10 +189,108 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment {
return true;
}
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
mKeyboardShortcutHandler.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
builder.setPositiveButton(getContext().getString(android.R.string.ok), this);
builder.setNegativeButton(getContext().getString(android.R.string.cancel), this);
builder.setNeutralButton(getContext().getString(R.string.clear), this);
builder.setOnKeyListener(this);
}
@Override
protected void onPrepareForRemoval() {
mKeyboardShortcutHandler.unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
super.onPrepareForRemoval();
}
@Override
protected View onCreateDialogView() {
final View view = super.onCreateDialogView();
mKeysLabel = (TextView) view.findViewById(R.id.keys_label);
mConflictLabel = (TextView) view.findViewById(R.id.conflict_label);
mConflictLabel.setVisibility(View.GONE);
return view;
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
if (mKeySpec == null) return;
mKeyboardShortcutHandler.register(mKeySpec, mAction);
break;
}
case DialogInterface.BUTTON_NEUTRAL: {
mKeyboardShortcutHandler.unregister(mAction);
break;
}
}
}
private void updateSummary() {
final KeyboardShortcutSpec spec = mKeyboardShortcutHandler.findKey(mAction);
setSummary(spec != null ? spec.toKeyString() : null);
}
}
private static class KeyboardShortcutPreferenceCompat extends Preference {
private final KeyboardShortcutsHandler mKeyboardShortcutHandler;
private final String mContextTag, mAction;
private final OnSharedPreferenceChangeListener mPreferencesChangeListener;
public KeyboardShortcutPreferenceCompat(final Context context, final KeyboardShortcutsHandler handler,
@Nullable final String contextTag, @NonNull final String action) {
//noinspection ConstantConditions
super(context, null);
mKeyboardShortcutHandler = handler;
mContextTag = contextTag;
mAction = action;
setPersistent(false);
setTitle(KeyboardShortcutsHandler.getActionLabel(context, action));
mPreferencesChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updateSummary();
}
};
updateSummary();
}
@Override
protected void onClick() {
final Context context = getContext();
final Intent intent = new Intent(context, KeyboardShortcutPreferenceCompatActivity.class);
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_CONTEXT_TAG, mContextTag);
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_KEY_ACTION, mAction);
context.startActivity(intent);
}
@Override
protected void onAttachedToActivity() {
super.onAttachedToActivity();
mKeyboardShortcutHandler.registerOnSharedPreferenceChangeListener(mPreferencesChangeListener);
}
@Override
protected void onPrepareForRemoval() {
mKeyboardShortcutHandler.unregisterOnSharedPreferenceChangeListener(mPreferencesChangeListener);
super.onPrepareForRemoval();
}
private void updateSummary() {
final KeyboardShortcutSpec spec = mKeyboardShortcutHandler.findKey(mAction);
setSummary(spec != null ? spec.toKeyString() : null);
}
}
public static class ResetKeyboardShortcutConfirmDialogFragment extends DialogFragment implements OnClickListener {

View File

@ -249,7 +249,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentListFragment<A
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMedia(getActivity(), status, media, options);
//spice
SpiceProfilingUtil.log(getActivity(),
SpiceProfilingUtil.log(
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + adapter.isMediaPreviewEnabled() + "," + status.timestamp);

View File

@ -298,7 +298,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
if (status == null) return;
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMedia(getActivity(), status, media, options);
SpiceProfilingUtil.log(getActivity(),
SpiceProfilingUtil.log(
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.preview_url + "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + mStatusAdapter.isMediaPreviewEnabled() + "," + status.timestamp);
@ -383,7 +383,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMediaDirectly(getActivity(), accountId, status, media, status.media, options);
//spice
SpiceProfilingUtil.log(getActivity(),
SpiceProfilingUtil.log(
status.id + ",Clicked," + status.account_id + "," + status.user_id + "," + status.text_plain.length()
+ "," + media.preview_url + "," + media.media_url + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + mStatusAdapter.isMediaPreviewEnabled() + "," + status.timestamp);
@ -444,7 +444,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
status.id + ",Words," + status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.text_plain.length() + "," + status.timestamp);
SpiceProfilingUtil.log(getActivity(), status.id + ",Words," + status.account_id + "," + status.user_id
SpiceProfilingUtil.log(status.id + ",Words," + status.account_id + "," + status.user_id
+ "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + status.text_plain.length() + "," + status.timestamp);
} else {
@ -456,7 +456,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
+ "," + status.text_plain.length() + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + media.media_url + "," + media.width + "x" + media.height
+ "," + status.timestamp);
SpiceProfilingUtil.log(getActivity(),
SpiceProfilingUtil.log(
status.id + ",PreviewM," + status.account_id + "," + status.user_id
+ "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + status.text_plain.length() + "," + TypeMappingUtil.getMediaType(media.type)
@ -468,7 +468,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
+ "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + status.text_plain.length() + "," + TypeMappingUtil.getMediaType(media.type)
+ "," + media.preview_url + "," + media.media_url + "," + status.timestamp);
SpiceProfilingUtil.log(getActivity(),
SpiceProfilingUtil.log(
status.id + ",PreviewO," + status.account_id + "," + status.user_id
+ "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + status.text_plain.length() + "," + TypeMappingUtil.getMediaType(media.type)

View File

@ -321,13 +321,13 @@ public class BackgroundOperationService extends IntentService implements Constan
failedAccountIds.remove(response.getData().account_id);
//spice
if (response.getData().media == null) {
SpiceProfilingUtil.log(this.getBaseContext(), response.getData().id + ",Tweet," + response.getData().account_id + ","
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(this.getBaseContext(), response.getData().id + ",Media," + response.getData().account_id + ","
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));

View File

@ -913,7 +913,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
+ status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
SpiceProfilingUtil.log(context, status.id + ",Favor,"
SpiceProfilingUtil.log(status.id + ",Favor,"
+ status.account_id + "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count + "," + status.timestamp);
//end
@ -1468,7 +1468,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
+ "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
SpiceProfilingUtil.log(context, status.id + ",Unfavor," + status.account_id
SpiceProfilingUtil.log(status.id + ",Unfavor," + status.account_id
+ "," + status.user_id + "," + status.reply_count
+ "," + status.retweet_count + "," + status.favorite_count
+ "," + status.timestamp);
@ -2377,21 +2377,21 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
//spice
if (status.media == null) {
SpiceProfilingUtil.log(getContext(), status.id + ",Retweet," + account_id + ","
SpiceProfilingUtil.log(status.id + ",Retweet," + account_id + ","
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count);
SpiceProfilingUtil.profile(getContext(), account_id, status.id + ",Retweet," + account_id + ","
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count);
} else {
for (final ParcelableMedia spiceMedia : status.media) {
if (spiceMedia.type == ParcelableMedia.TYPE_IMAGE) {
SpiceProfilingUtil.log(getContext(), status.id + ",RetweetM," + account_id + ","
SpiceProfilingUtil.log(status.id + ",RetweetM," + account_id + ","
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + spiceMedia.media_url + "," + TypeMappingUtil.getMediaType(spiceMedia.type) + "," + spiceMedia.width + "x" + spiceMedia.height);
SpiceProfilingUtil.profile(getContext(), account_id, status.id + ",RetweetM," + account_id + ","
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + spiceMedia.preview_url + "," + spiceMedia.media_url + "," + TypeMappingUtil.getMediaType(spiceMedia.type) + "," + spiceMedia.width + "x" + spiceMedia.height);
} else {
SpiceProfilingUtil.log(getContext(), status.id + ",RetweetO," + account_id + ","
SpiceProfilingUtil.log(status.id + ",RetweetO," + account_id + ","
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
+ "," + spiceMedia.media_url + "," + TypeMappingUtil.getMediaType(spiceMedia.type));
SpiceProfilingUtil.profile(getContext(), account_id, status.id + ",RetweetO," + account_id + ","

View File

@ -42,6 +42,7 @@ public class KeyboardShortcutsHandler implements Constants {
sActionLabelMap.put("compose", R.string.compose);
sActionLabelMap.put("search", R.string.search);
sActionLabelMap.put("message", R.string.new_direct_message);
sActionLabelMap.put("home.accounts_dashboard", R.string.open_accounts_dashboard);
sActionLabelMap.put("status.reply", R.string.reply);
sActionLabelMap.put("status.retweet", R.string.retweet);
sActionLabelMap.put("status.favorite", R.string.favorite);
@ -216,6 +217,7 @@ public class KeyboardShortcutsHandler implements Constants {
editor.putString("n", "compose");
editor.putString("m", "message");
editor.putString("slash", "search");
editor.putString("home.q", "home.accounts_dashboard");
editor.putString("navigation.period", "navigation.refresh");
editor.putString("navigation.j", "navigation.next");
editor.putString("navigation.k", "navigation.previous");
@ -280,6 +282,10 @@ public class KeyboardShortcutsHandler implements Constants {
this.action = action;
}
public KeyboardShortcutSpec copy() {
return new KeyboardShortcutSpec(contextTag, keyMeta, keyName, action);
}
public String getContextTag() {
return contextTag;
}
@ -308,6 +314,10 @@ public class KeyboardShortcutsHandler implements Constants {
return keyName != null;
}
public void setContextTag(String contextTag) {
this.contextTag = contextTag;
}
public String toKeyString() {
return metaToFriendlyString(keyMeta) + keyToFriendlyString(keyName);
}

View File

@ -35,7 +35,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@ -56,6 +55,7 @@ import android.net.NetworkInfo;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.os.AsyncTask;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
@ -172,6 +172,7 @@ import org.mariotaku.twidere.graphic.ActionIconDrawable;
import org.mariotaku.twidere.graphic.PaddingDrawable;
import org.mariotaku.twidere.menu.SupportStatusShareProvider;
import org.mariotaku.twidere.model.AccountPreferences;
import org.mariotaku.twidere.model.ConsumerKeyType;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
@ -2511,11 +2512,7 @@ public final class Utils implements Constants, TwitterConstants {
cb.setSigningUploadBaseURL(DEFAULT_SIGNING_UPLOAD_BASE_URL);
}
}
if (TwitterContentUtils.isOfficialKey(context, consumerKey, consumerSecret)) {
setMockOfficialUserAgent(context, cb);
} else {
setUserAgent(context, cb);
}
setClientUserAgent(context, consumerKey, consumerSecret, cb);
cb.setIncludeEntitiesEnabled(includeEntities);
cb.setIncludeRTsEnabled(includeRetweets);
@ -2685,17 +2682,6 @@ public final class Utils implements Constants, TwitterConstants {
return BuildConfig.DEBUG;
}
public static boolean isDebuggable(final Context context) {
if (context == null) return false;
final ApplicationInfo info;
try {
info = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
} catch (final NameNotFoundException e) {
return false;
}
return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
public static boolean isFiltered(final SQLiteDatabase database, final long user_id, final String text_plain,
final String text_html, final String source, final long retweeted_by_id) {
return isFiltered(database, user_id, text_plain, text_html, source, retweeted_by_id, true);
@ -3600,28 +3586,58 @@ public final class Utils implements Constants, TwitterConstants {
* TwitterAndroid/[versionName] ([versionCode]-[buildName]-[r|d)]-[buildNumber]) [deviceInfo]
*
* @param context
* @param consumerKey
* @param consumerSecret
* @param cb
*/
public static void setMockOfficialUserAgent(final Context context, final ConfigurationBuilder cb) {
final PackageManager pm = context.getPackageManager();
cb.setClientName("TwitterAndroid");
cb.setClientURL(null);
String versionName;
int versionCode;
try {
final PackageInfo packageInfo = pm.getPackageInfo("com.twitter.android", 0);
versionName = packageInfo.versionName;
versionCode = packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
versionName = "5.53.0";
versionCode = 4030814;
public static void setClientUserAgent(final Context context, String consumerKey, String consumerSecret, final ConfigurationBuilder cb) {
final ConsumerKeyType officialKeyType = TwitterContentUtils.getOfficialKeyType(context, consumerKey, consumerSecret);
if (officialKeyType == ConsumerKeyType.UNKNOWN) {
setUserAgent(context, cb);
return;
}
cb.setClientVersion(versionName);
final String deviceInfo = String.format(Locale.ROOT, "%s/%s (%s;%s;%s;%s;)",
Build.MODEL, Build.VERSION.RELEASE, Build.MANUFACTURER, Build.MODEL, Build.BRAND,
Build.PRODUCT);
cb.setHttpUserAgent(String.format(Locale.ROOT, "TwitterAndroid/%s (%d-%c-%d) %s",
versionName, versionCode, 'r', versionCode / 4200, deviceInfo));
final String userAgentName = getUserAgentName(officialKeyType);
cb.setClientName(userAgentName);
cb.setClientURL(null);
cb.setClientVersion(null);
cb.setHttpUserAgent(userAgentName);
// final PackageManager pm = context.getPackageManager();
// final String clientName = "TwitterAndroid";
// cb.setClientName(clientName);
// cb.setClientURL(null);
// String versionName;
// int versionCode;
// try {
// final PackageInfo packageInfo = pm.getPackageInfo("com.twitter.android", 0);
// versionName = packageInfo.versionName;
// versionCode = packageInfo.versionCode;
// } catch (PackageManager.NameNotFoundException e) {
// versionName = "5.53.0";
// versionCode = 4030814;
// }
// cb.setClientVersion(versionName);
// final String deviceInfo = String.format(Locale.ROOT, "%s/%s (%s;%s;%s;%s;)", Build.MODEL,
// Build.VERSION.RELEASE, Build.MANUFACTURER, Build.MODEL, Build.BRAND, Build.PRODUCT);
// cb.setHttpUserAgent(String.format(Locale.ROOT, "%s/%s (%d-%c-%d) %s", clientName,
// versionName, versionCode, 'r', versionCode / 4200, deviceInfo));
}
private static String getUserAgentName(ConsumerKeyType type) {
switch (type) {
case TWITTER_FOR_ANDROID: {
return "TwitterAndroid";
}
case TWITTER_FOR_IPHONE: {
return "Twitter-iPhone";
}
case TWITTER_FOR_IPAD: {
return "Twitter-iPad";
}
case TWITTER_FOR_MAC: {
return "Twitter-Mac";
}
}
return "Twitter";
}
public static boolean shouldForceUsingPrivateAPIs(final Context context) {
@ -3793,14 +3809,19 @@ public final class Utils implements Constants, TwitterConstants {
public static void startRefreshServiceIfNeeded(final Context context) {
final Intent refreshServiceIntent = new Intent(context, RefreshService.class);
if (isNetworkAvailable(context) && hasAutoRefreshAccounts(context)) {
if (isDebugBuild()) {
Log.d(LOGTAG, "Start background refresh service");
AsyncTask.execute(new Runnable() {
@Override
public void run() {
if (isNetworkAvailable(context) && hasAutoRefreshAccounts(context)) {
if (isDebugBuild()) {
Log.d(LOGTAG, "Start background refresh service");
}
context.startService(refreshServiceIntent);
} else {
context.stopService(refreshServiceIntent);
}
}
context.startService(refreshServiceIntent);
} else {
context.stopService(refreshServiceIntent);
}
});
}
public static void startStatusShareChooser(final Context context, final ParcelableStatus status) {
@ -3838,10 +3859,10 @@ public final class Utils implements Constants, TwitterConstants {
}
public static boolean truncateMessages(final List<DirectMessage> in, final List<DirectMessage> out,
final long since_id) {
final long sinceId) {
if (in == null) return false;
for (final DirectMessage message : in) {
if (since_id > 0 && message.getId() <= since_id) {
if (sinceId > 0 && message.getId() <= sinceId) {
continue;
}
out.add(message);

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/keyboard_shortcut_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/element_spacing_xlarge">
<TextView
android:id="@+id/keys_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/keyboard_shortcut_hint"
android:textAppearance="?android:textAppearanceMedium"/>
<TextView
android:id="@+id/conflict_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout
android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:attr/dividerHorizontal"
android:dividerPadding="0dip"
android:minHeight="@dimen/element_size_normal"
android:orientation="vertical"
android:showDividers="beginning">
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="locale"
android:measureWithLargestChild="true"
android:orientation="horizontal">
<Button
android:id="@+id/button_negative"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_weight="1"
android:maxLines="2"
android:minHeight="@dimen/element_size_normal"
android:text="@android:string/cancel"
android:textSize="14sp"/>
<Button
android:id="@+id/button_neutral"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:maxLines="2"
android:minHeight="@dimen/element_size_normal"
android:text="@string/clear"
android:textSize="14sp"/>
<Button
android:id="@+id/button_positive"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_weight="1"
android:maxLines="2"
android:minHeight="@dimen/element_size_normal"
android:text="@android:string/ok"
android:textSize="14sp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -24,20 +24,21 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/element_spacing_xlarge">
<TextView
android:id="@+id/keys_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/keyboard_shortcut_hint"/>
android:text="@string/keyboard_shortcut_hint"
android:textAppearance="?android:textAppearanceMedium"/>
<TextView
android:id="@+id/conflict_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:visibility="gone"/>
</org.mariotaku.twidere.view.ExtendedLinearLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<resources>
<dimen name="drawer_offset_home">128dp</dimen>
</resources>

View File

@ -730,5 +730,6 @@
<string name="navigation">Navigation</string>
<string name="reset_to_default">Reset to default</string>
<string name="reset_keyboard_shortcuts_confirm">Reset keyboard shortcuts to default?</string>
<string name="open_accounts_dashboard">Open accounts dashboard</string>
</resources>