/* * Twidere - Twitter client for Android * * Copyright (C) 2012-2014 Mariotaku Lee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.mariotaku.twidere.app; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.PackageManager; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.AsyncTask; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.multidex.MultiDexApplication; import com.nostra13.universalimageloader.cache.disc.DiskCache; import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import com.nostra13.universalimageloader.core.download.ImageDownloader; import com.nostra13.universalimageloader.utils.L; import com.squareup.okhttp.internal.Network; import com.squareup.otto.Bus; import org.acra.annotation.ReportsCrashes; import org.mariotaku.twidere.BuildConfig; import org.mariotaku.twidere.Constants; import org.mariotaku.twidere.activity.AssistLauncherActivity; import org.mariotaku.twidere.activity.MainActivity; import org.mariotaku.twidere.activity.MainHondaJOJOActivity; import org.mariotaku.twidere.service.RefreshService; import org.mariotaku.twidere.util.AbsLogger; import org.mariotaku.twidere.util.AsyncTaskManager; import org.mariotaku.twidere.util.DebugModeUtils; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; import org.mariotaku.twidere.util.MathUtils; import org.mariotaku.twidere.util.MediaLoaderWrapper; import org.mariotaku.twidere.util.MultiSelectManager; import org.mariotaku.twidere.util.StrictModeUtils; import org.mariotaku.twidere.util.TwidereLogger; import org.mariotaku.twidere.util.UserColorNameManager; import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.VideoLoader; import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper; import org.mariotaku.twidere.util.dagger.ApplicationModule; import org.mariotaku.twidere.util.imageloader.ReadOnlyDiskLRUNameCache; import org.mariotaku.twidere.util.imageloader.TwidereImageDownloader; import org.mariotaku.twidere.util.imageloader.URLFileNameGenerator; import org.mariotaku.twidere.util.net.TwidereHostAddressResolver; import java.io.File; import java.io.IOException; import edu.tsinghua.hotmobi.HotMobiLogger; import static org.mariotaku.twidere.util.Utils.getBestCacheDir; import static org.mariotaku.twidere.util.Utils.getInternalCacheDir; import static org.mariotaku.twidere.util.Utils.initAccountColor; import static org.mariotaku.twidere.util.Utils.startRefreshServiceIfNeeded; @ReportsCrashes(formUri = "https://twidere-bugreport.herokuapp.com/reports", buildConfigClass = BuildConfig.class) public class TwidereApplication extends MultiDexApplication implements Constants, OnSharedPreferenceChangeListener { private static final String KEY_UCD_DATA_PROFILING = "ucd_data_profiling"; private static final String KEY_SPICE_DATA_PROFILING = "spice_data_profiling"; private static final String KEY_KEYBOARD_SHORTCUT_INITIALIZED = "keyboard_shortcut_initialized"; private Handler mHandler; private MediaLoaderWrapper mMediaLoaderWrapper; private ImageLoader mImageLoader; private AsyncTaskManager mAsyncTaskManager; private SharedPreferences mPreferences; private MultiSelectManager mMultiSelectManager; private TwidereImageDownloader mImageDownloader, mFullImageDownloader; private DiskCache mDiskCache, mFullDiskCache; private SQLiteOpenHelper mSQLiteOpenHelper; private Network mNetwork; private SQLiteDatabase mDatabase; private Bus mMessageBus; private VideoLoader mVideoLoader; private KeyboardShortcutsHandler mKeyboardShortcutsHandler; private UserColorNameManager mUserColorNameManager; private HotMobiLogger mHotMobiLogger; private ApplicationModule mApplicationModule; @NonNull public static TwidereApplication getInstance(@NonNull final Context context) { return (TwidereApplication) context.getApplicationContext(); } public AsyncTaskManager getAsyncTaskManager() { if (mAsyncTaskManager != null) return mAsyncTaskManager; return mAsyncTaskManager = AsyncTaskManager.getInstance(); } public DiskCache getDiskCache() { if (mDiskCache != null) return mDiskCache; return mDiskCache = createDiskCache(DIR_NAME_IMAGE_CACHE); } public DiskCache getFullDiskCache() { if (mFullDiskCache != null) return mFullDiskCache; return mFullDiskCache = createDiskCache(DIR_NAME_FULL_IMAGE_CACHE); } public UserColorNameManager getUserColorNameManager() { if (mUserColorNameManager != null) return mUserColorNameManager; return mUserColorNameManager = new UserColorNameManager(this); } public ImageDownloader getFullImageDownloader() { if (mFullImageDownloader != null) return mFullImageDownloader; return mFullImageDownloader = new TwidereImageDownloader(this, true, true); } public Handler getHandler() { return mHandler; } public Network getNetwork() { if (mNetwork != null) return mNetwork; return mNetwork = new TwidereHostAddressResolver(this); } public KeyboardShortcutsHandler getKeyboardShortcutsHandler() { if (mKeyboardShortcutsHandler != null) return mKeyboardShortcutsHandler; mKeyboardShortcutsHandler = new KeyboardShortcutsHandler(this); final SharedPreferences preferences = getSharedPreferences(); if (!preferences.getBoolean(KEY_KEYBOARD_SHORTCUT_INITIALIZED, false)) { mKeyboardShortcutsHandler.reset(); preferences.edit().putBoolean(KEY_KEYBOARD_SHORTCUT_INITIALIZED, true).apply(); } return mKeyboardShortcutsHandler; } public ImageDownloader getImageDownloader() { if (mImageDownloader != null) return mImageDownloader; return mImageDownloader = new TwidereImageDownloader(this, false, true); } public ImageLoader getImageLoader() { if (mImageLoader != null) return mImageLoader; final ImageLoader loader = ImageLoader.getInstance(); final ImageLoaderConfiguration.Builder cb = new ImageLoaderConfiguration.Builder(this); cb.threadPriority(Thread.NORM_PRIORITY - 2); cb.denyCacheImageMultipleSizesInMemory(); cb.tasksProcessingOrder(QueueProcessingType.LIFO); // cb.memoryCache(new ImageMemoryCache(40)); cb.diskCache(getDiskCache()); cb.imageDownloader(getImageDownloader()); L.writeDebugLogs(BuildConfig.DEBUG); loader.init(cb.build()); return mImageLoader = loader; } public VideoLoader getVideoLoader() { if (mVideoLoader != null) return mVideoLoader; final VideoLoader loader = new VideoLoader(this); return mVideoLoader = loader; } public MediaLoaderWrapper getMediaLoaderWrapper() { if (mMediaLoaderWrapper != null) return mMediaLoaderWrapper; return mMediaLoaderWrapper = new MediaLoaderWrapper(getImageLoader(), getVideoLoader()); } @Nullable public Bus getMessageBus() { return mMessageBus; } public MultiSelectManager getMultiSelectManager() { if (mMultiSelectManager != null) return mMultiSelectManager; return mMultiSelectManager = new MultiSelectManager(); } public SQLiteDatabase getSQLiteDatabase() { if (mDatabase != null) return mDatabase; StrictModeUtils.checkDiskIO(); return mDatabase = getSQLiteOpenHelper().getWritableDatabase(); } public SQLiteOpenHelper getSQLiteOpenHelper() { if (mSQLiteOpenHelper != null) return mSQLiteOpenHelper; return mSQLiteOpenHelper = new TwidereSQLiteOpenHelper(this, DATABASES_NAME, DATABASES_VERSION); } @Override public void onCreate() { if (BuildConfig.DEBUG) { StrictModeUtils.detectAllVmPolicy(); } super.onCreate(); initDebugMode(); initBugReport(); mHandler = new Handler(); mMessageBus = new Bus(); initializeAsyncTask(); initAccountColor(this); final PackageManager pm = getPackageManager(); final ComponentName main = new ComponentName(this, MainActivity.class); final ComponentName main2 = new ComponentName(this, MainHondaJOJOActivity.class); final boolean mainDisabled = pm.getComponentEnabledSetting(main) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED; final boolean main2Disabled = pm.getComponentEnabledSetting(main2) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED; final boolean noEntry = mainDisabled && main2Disabled; if (noEntry) { pm.setComponentEnabledSetting(main, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } else if (!mainDisabled) { pm.setComponentEnabledSetting(main2, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } if (!Utils.isComposeNowSupported(this)) { final ComponentName assist = new ComponentName(this, AssistLauncherActivity.class); pm.setComponentEnabledSetting(assist, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } migrateUsageStatisticsPreferences(); startRefreshServiceIfNeeded(this); reloadConnectivitySettings(); } private void initDebugMode() { DebugModeUtils.initForApplication(this); } private void initBugReport() { final SharedPreferences preferences = getSharedPreferences(); if (!preferences.getBoolean(KEY_BUG_REPORTS, true)) return; if (!BuildConfig.DEBUG) { AbsLogger.setImplementation(new TwidereLogger()); } AbsLogger.init(this); } private void migrateUsageStatisticsPreferences() { final SharedPreferences preferences = getSharedPreferences(); final boolean hasUsageStatistics = preferences.contains(KEY_USAGE_STATISTICS); if (hasUsageStatistics) return; if (preferences.contains(KEY_UCD_DATA_PROFILING) || preferences.contains(KEY_SPICE_DATA_PROFILING)) { final boolean prevUsageEnabled = preferences.getBoolean(KEY_UCD_DATA_PROFILING, false) || preferences.getBoolean(KEY_SPICE_DATA_PROFILING, false); final Editor editor = preferences.edit(); editor.putBoolean(KEY_USAGE_STATISTICS, prevUsageEnabled); editor.remove(KEY_UCD_DATA_PROFILING); editor.remove(KEY_SPICE_DATA_PROFILING); editor.apply(); } } private SharedPreferences getSharedPreferences() { if (mPreferences != null) return mPreferences; mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE); mPreferences.registerOnSharedPreferenceChangeListener(this); return mPreferences; } @Override public void onLowMemory() { if (mMediaLoaderWrapper != null) { mMediaLoaderWrapper.clearMemoryCache(); } super.onLowMemory(); } @Override public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) { if (KEY_REFRESH_INTERVAL.equals(key)) { stopService(new Intent(this, RefreshService.class)); startRefreshServiceIfNeeded(this); } else if (KEY_ENABLE_PROXY.equals(key) || KEY_CONNECTION_TIMEOUT.equals(key) || KEY_PROXY_HOST.equals(key) || KEY_PROXY_PORT.equals(key)) { reloadConnectivitySettings(); } else if (KEY_CONSUMER_KEY.equals(key) || KEY_CONSUMER_SECRET.equals(key) || KEY_API_URL_FORMAT.equals(key) || KEY_AUTH_TYPE.equals(key) || KEY_SAME_OAUTH_SIGNING_URL.equals(key) || KEY_THUMBOR_ENABLED.equals(key) || KEY_THUMBOR_ADDRESS.equals(key) || KEY_THUMBOR_SECURITY_KEY.equals(key)) { final SharedPreferences.Editor editor = preferences.edit(); editor.putLong(KEY_API_LAST_CHANGE, System.currentTimeMillis()); editor.apply(); } } public void reloadConnectivitySettings() { if (mImageDownloader != null) { mImageDownloader.reloadConnectivitySettings(); } if (mFullImageDownloader != null) { mFullImageDownloader.reloadConnectivitySettings(); } } private DiskCache createDiskCache(final String dirName) { final File cacheDir = getBestCacheDir(this, dirName); final File fallbackCacheDir = getInternalCacheDir(this, dirName); final URLFileNameGenerator fileNameGenerator = new URLFileNameGenerator(); final SharedPreferences preferences = getSharedPreferences(); final int cacheSize = MathUtils.clamp(preferences.getInt(KEY_CACHE_SIZE_LIMIT, 300), 100, 500); try { return new LruDiskCache(cacheDir, fallbackCacheDir, fileNameGenerator, cacheSize * 1024 * 1024, 0); } catch (IOException e) { return new ReadOnlyDiskLRUNameCache(cacheDir, fallbackCacheDir, fileNameGenerator); } } private void initializeAsyncTask() { // AsyncTask class needs to be loaded in UI thread. // So we load it here to comply the rule. try { Class.forName(AsyncTask.class.getName()); } catch (final ClassNotFoundException ignore) { } } @NonNull public HotMobiLogger getHotMobiLogger() { if (mHotMobiLogger != null) return mHotMobiLogger; return mHotMobiLogger = new HotMobiLogger(this); } public static ApplicationModule getModule(Context context) { return getInstance(context).getApplicationModule(); } private ApplicationModule getApplicationModule() { if (mApplicationModule != null) return mApplicationModule; return mApplicationModule = new ApplicationModule(this); } }