SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/App1.java

349 lines
13 KiB
Java

package jp.juggler.subwaytooter;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
import com.bumptech.glide.load.model.GlideUrl;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import jp.juggler.subwaytooter.table.AcctColor;
import jp.juggler.subwaytooter.table.AcctSet;
import jp.juggler.subwaytooter.table.MutedApp;
import jp.juggler.subwaytooter.table.ClientInfo;
import jp.juggler.subwaytooter.table.ContentWarning;
import jp.juggler.subwaytooter.table.LogData;
import jp.juggler.subwaytooter.table.MediaShown;
import jp.juggler.subwaytooter.table.MutedWord;
import jp.juggler.subwaytooter.table.NotificationTracking;
import jp.juggler.subwaytooter.table.PostDraft;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.table.UserRelation;
import jp.juggler.subwaytooter.util.LogCategory;
import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
import uk.co.chrisjenx.calligraphy.TypefaceUtils;
public class App1 extends Application {
static final LogCategory log = new LogCategory( "App1" );
static final String DB_NAME = "app_db";
static final int DB_VERSION = 13;
// 2017/4/25 v10 1=>2 SavedAccount に通知設定を追加
// 2017/4/25 v10 1=>2 NotificationTracking テーブルを追加
// 2017/4/29 v20 2=>5 MediaShown,ContentWarningのインデクスが間違っていたので貼り直す
// 2017/4/29 v23 5=>6 MutedAppテーブルの追加、UserRelationテーブルの追加
// 2017/5/01 v26 6=>7 AcctSetテーブルの追加
// 2017/5/02 v32 7=>8 (この変更は取り消された)
// 2017/5/02 v32 8=>9 AcctColor テーブルの追加
// 2017/5/04 v33 9=>10 SavedAccountに項目追加
// 2017/5/08 v41 10=>11 MutedWord テーブルの追加
// 2017/5/17 v59 11=>12 PostDraft テーブルの追加
// 2017/5/23 v68 12=>13 SavedAccountに項目追加
private static DBOpenHelper db_open_helper;
public static SQLiteDatabase getDB(){
return db_open_helper.getWritableDatabase();
}
public static void setActivityTheme( Activity activity, boolean bNoActionBar ){
int theme_idx = pref.getInt( Pref.KEY_UI_THEME, 0 );
switch( theme_idx ){
default:
case 0:
activity.setTheme( bNoActionBar ? R.style.AppTheme_Light_NoActionBar : R.style.AppTheme_Light );
break;
case 1:
activity.setTheme( bNoActionBar ? R.style.AppTheme_Dark_NoActionBar : R.style.AppTheme_Dark );
break;
}
}
public static void prepareDB( Context applicationContext ){
if( db_open_helper == null ){
db_open_helper = new DBOpenHelper( applicationContext );
// if( BuildConfig.DEBUG){
// SQLiteDatabase db = db_open_helper.getWritableDatabase();
// db_open_helper.onCreate( db );
// }
UserRelation.deleteOld( System.currentTimeMillis() );
AcctSet.deleteOld( System.currentTimeMillis() );
}
}
private static class DBOpenHelper extends SQLiteOpenHelper {
private DBOpenHelper( Context context ){
super( context, DB_NAME, null, DB_VERSION );
}
@Override
public void onCreate( SQLiteDatabase db ){
LogData.onDBCreate( db );
//
SavedAccount.onDBCreate( db );
ClientInfo.onDBCreate( db );
MediaShown.onDBCreate( db );
ContentWarning.onDBCreate( db );
NotificationTracking.onDBCreate( db );
MutedApp.onDBCreate( db );
UserRelation.onDBCreate( db );
AcctSet.onDBCreate( db );
AcctColor.onDBCreate( db );
MutedWord.onDBCreate( db );
PostDraft.onDBCreate( db );
}
@Override
public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
LogData.onDBUpgrade( db, oldVersion, newVersion );
//
SavedAccount.onDBUpgrade( db, oldVersion, newVersion );
ClientInfo.onDBUpgrade( db, oldVersion, newVersion );
MediaShown.onDBUpgrade( db, oldVersion, newVersion );
ContentWarning.onDBUpgrade( db, oldVersion, newVersion );
NotificationTracking.onDBUpgrade( db, oldVersion, newVersion );
MutedApp.onDBUpgrade( db, oldVersion, newVersion );
UserRelation.onDBUpgrade( db, oldVersion, newVersion );
AcctSet.onDBUpgrade( db, oldVersion, newVersion );
AcctColor.onDBUpgrade( db, oldVersion, newVersion );
MutedWord.onDBUpgrade( db, oldVersion, newVersion );
PostDraft.onDBUpgrade( db, oldVersion, newVersion );
}
}
@SuppressWarnings("unused")
private static final CipherSuite[] APPROVED_CIPHER_SUITES = new CipherSuite[]{
// 以下は okhttp 3 のデフォルト
// This is nearly equal to the cipher suites supported in Chrome 51, current as of 2016-05-25.
// All of these suites are available on Android 7.0; earlier releases support a subset of these
// suites. https://github.com/square/okhttp/issues/1972
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// Note that the following cipher suites are all on HTTP/2's bad cipher suites list. We'll
// continue to include them until better suites are commonly available. For example, none
// of the better cipher suites listed above shipped with Android 4.4 or Java 7.
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
//https://www.ssllabs.com/ssltest/analyze.html?d=mastodon.cloud&latest
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,// mastodon.cloud用 デフォルトにはない
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, //mastodon.cloud用 デフォルトにはない
// https://www.ssllabs.com/ssltest/analyze.html?d=m.sighash.info
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, // m.sighash.info 用 デフォルトにはない
CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, // m.sighash.info 用 デフォルトにはない
CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, // m.sighash.info 用 デフォルトにはない
CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, // m.sighash.info 用 デフォルトにはない
};
// private int getBitmapPoolSize( Context context ){
// ActivityManager am = ((ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE));
// int memory = am.getMemoryClass();
// int largeMemory = am.getLargeMemoryClass();
// // どちらも単位はMB
// log.d("MemoryClass=%d, LargeMemoryClass = %d",memory,largeMemory);
//
// int maxSize;
// if( am.isLowRamDevice() ){
// maxSize = 5 * 1024; // 単位はKiB
// }else if( largeMemory >= 512 ){
// maxSize = 128 * 1024; // 単位はKiB
// }else if( largeMemory >= 256 ){
// maxSize = 64 * 1024; // 単位はKiB
// }else{
// maxSize = 10 * 1024; // 単位はKiB
// }
// return maxSize * 1024;
// }
public static OkHttpClient ok_http_client;
public static Typeface typeface_emoji;
public static SharedPreferences pref;
public static ThreadPoolExecutor task_executor;
static OkHttpUrlLoader.Factory glide_okhttp3_factory;
@Override
public void onCreate(){
super.onCreate();
CalligraphyConfig.initDefault( new CalligraphyConfig.Builder()
.setFontAttrId( R.attr.fontPath )
.build()
);
if( task_executor == null ){
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
int CPU_COUNT = Runtime.getRuntime().availableProcessors();
int CORE_POOL_SIZE = Math.max( 2, Math.min( CPU_COUNT - 1, 4 ) );
int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
int KEEP_ALIVE_SECONDS = 30;
// デフォルトだとキューはmax128で、溢れることがある
BlockingQueue< Runnable > sPoolWorkQueue = new LinkedBlockingQueue<>( 999 );
ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger( 1 );
public Thread newThread( @NonNull Runnable r ){
return new Thread( r, "SubwayTooterTask #" + mCount.getAndIncrement() );
}
};
task_executor = new ThreadPoolExecutor(
CORE_POOL_SIZE // pool size
, MAXIMUM_POOL_SIZE // max pool size
, KEEP_ALIVE_SECONDS // keep-alive-seconds
, TimeUnit.SECONDS // unit of keep-alive-seconds
, sPoolWorkQueue
, sThreadFactory
);
task_executor.allowCoreThreadTimeOut( true );
}
if( pref == null ){
pref = Pref.pref( getApplicationContext() );
}
prepareDB(getApplicationContext());
if( typeface_emoji == null ){
typeface_emoji = TypefaceUtils.load( getAssets(), "emojione_android.ttf" );
}
// if( image_loader == null ){
// image_loader = new MyImageLoader(
// Volley.newRequestQueue( getApplicationContext() )
// , new BitmapCache( getApplicationContext() )
// );
// }
if( ok_http_client == null ){
ConnectionSpec spec = new ConnectionSpec.Builder( ConnectionSpec.MODERN_TLS )
.cipherSuites( APPROVED_CIPHER_SUITES )
.build();
ArrayList< ConnectionSpec > spec_list = new ArrayList<>();
spec_list.add( spec );
spec_list.add( ConnectionSpec.CLEARTEXT );
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout( 30, TimeUnit.SECONDS )
.readTimeout( 30, TimeUnit.SECONDS )
.writeTimeout( 30, TimeUnit.SECONDS )
.connectionSpecs( spec_list );
ok_http_client = builder.build();
}
// Glide.isSetup は Glide 4.0 で廃止になるらしいが、俺が使ってるのは3.xだ
//noinspection deprecation
if( ! Glide.isSetup() ){
Context context = getApplicationContext();
GlideBuilder builder = new GlideBuilder( context );
builder.setDiskCache( new InternalCacheDiskCacheFactory( context, 10 * 1024 * 1024 ) );
// 割とGlide任せで十分いけるっぽい
// MemorySizeCalculator calculator = new MemorySizeCalculator(context);
// int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
// int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
//
// ActivityManager am = ((ActivityManager)context.getSystemService(Activity.ACTIVITY_SERVICE));
// int class_memory = am.getMemoryClass(); // 単位はMB
// int class_large = am.getLargeMemoryClass(); // 単位はMB
//
// int maxSize;
// if( am.isLowRamDevice() ){
// maxSize = 5 * 1024; // 単位はKiB
// }else if( largeMemory >= 512 ){
// maxSize = 128 * 1024; // 単位はKiB
// }else if( largeMemory >= 256 ){
// maxSize = 64 * 1024; // 単位はKiB
// }else{
// maxSize = 10 * 1024; // 単位はKiB
// }
// return maxSize * 1024;
// }
// builder.setMemoryCache(new LruResourceCache(getMemoryCacheSize(getApplicationContext())));
// builder.setBitmapPool(new LruBitmapPool(getBitmapPoolSize(getApplicationContext())));
// Glide.setupはGLide 4.0 で廃止になるらしいが、俺が使ってるのは3.xだ
//noinspection deprecation
Glide.setup( builder );
glide_okhttp3_factory = new OkHttpUrlLoader.Factory( ok_http_client );
Glide.get( getApplicationContext() ).register( GlideUrl.class, InputStream.class, glide_okhttp3_factory );
}
}
@Override
public void onTerminate(){
super.onTerminate();
}
@SuppressLint("StaticFieldLeak")
private static AppState app_state;
static AppState getAppState( Context context ){
if( app_state == null ){
app_state = new AppState( context.getApplicationContext(), pref );
}
return app_state;
}
}