/* * Copyright 2016 Hippo Seven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hippo.ehviewer; import android.app.Activity; import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.os.Debug; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.LruCache; import android.util.Log; import android.util.SparseArray; import com.hippo.beerbelly.SimpleDiskCache; import com.hippo.conaco.Conaco; import com.hippo.ehviewer.client.EhClient; import com.hippo.ehviewer.client.EhCookieStore; import com.hippo.ehviewer.client.EhEngine; import com.hippo.ehviewer.client.data.GalleryDetail; import com.hippo.ehviewer.download.DownloadManager; import com.hippo.ehviewer.spider.SpiderDen; import com.hippo.ehviewer.ui.CommonOperations; import com.hippo.network.StatusCodeException; import com.hippo.okhttp.CookieDB; import com.hippo.scene.SceneApplication; import com.hippo.text.Html; import com.hippo.util.ReadableTime; import com.hippo.yorozuya.FileUtils; import com.hippo.yorozuya.SimpleHandler; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import okhttp3.OkHttpClient; public class EhApplication extends SceneApplication implements Thread.UncaughtExceptionHandler { private static final String TAG = EhApplication.class.getSimpleName(); public static final boolean BETA = true; private static final boolean DEBUG_CONACO = false; private static final boolean DEBUG_NATIVE_MEMORY = false; private Thread.UncaughtExceptionHandler mDefaultHandler; private final AtomicInteger mIdGenerator = new AtomicInteger(); private final SparseArray mGlobalStuffMap = new SparseArray<>(); private EhCookieStore mEhCookieStore; private EhClient mEhClient; private OkHttpClient mOkHttpClient; private BitmapHelper mBitmapHelper; private Conaco mConaco; private LruCache mGalleryDetailCache; private SimpleDiskCache mSpiderInfoCache; private DownloadManager mDownloadManager; private final List mActivityList = new ArrayList<>(); @Override public void onCreate() { // Prepare to catch crash mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); super.onCreate(); GetText.initialize(this); CookieDB.initialize(this); StatusCodeException.initialize(this); Settings.initialize(this); ReadableTime.initialize(this); Html.initialize(this); AppConfig.initialize(this); SpiderDen.initialize(this); EhDB.initialize(this); EhEngine.initialize(); if (EhDB.needMerge()) { EhDB.mergeOldDB(this); } if (Settings.getEnableAnalytics()) { Analytics.start(this); } CommonOperations.ensureNoMediaFile(Settings.getDownloadLocation()); // Update version code try { PackageInfo pi= getPackageManager().getPackageInfo(getPackageName(), 0); Settings.putVersionCode(pi.versionCode); } catch (PackageManager.NameNotFoundException e) { // Ignore } if (DEBUG_NATIVE_MEMORY) { debugNativeMemory(); } } public void clearMemoryCache() { if (null != mConaco) { mConaco.clearMemoryCache(); } if (null != mGalleryDetailCache) { mGalleryDetailCache.evictAll(); } } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) { clearMemoryCache(); } } private void debugNativeMemory() { new Runnable() { @Override public void run() { Log.i(TAG, "Native memory: " + FileUtils.humanReadableByteCount( Debug.getNativeHeapAllocatedSize(), false)); SimpleHandler.getInstance().postDelayed(this, 3000); } }.run(); } public int putGlobalStuff(@NonNull Object o) { int id = mIdGenerator.getAndDecrement(); mGlobalStuffMap.put(id, o); return id; } public boolean containGlobalStuff(int id) { return mGlobalStuffMap.indexOfKey(id) >= 0; } public Object getGlobalStuff(int id) { return mGlobalStuffMap.get(id); } public Object removeGlobalStuff(int id) { int index = mGlobalStuffMap.indexOfKey(id); if (index >= 0) { Object o = mGlobalStuffMap.valueAt(index); mGlobalStuffMap.removeAt(index); return o; } else { return null; } } public boolean removeGlobalStuff(Object o) { int index = mGlobalStuffMap.indexOfValue(o); if (index >= 0) { mGlobalStuffMap.removeAt(index); return true; } else { return false; } } public static EhCookieStore getEhCookieStore(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mEhCookieStore == null) { application.mEhCookieStore = new EhCookieStore(); } return application.mEhCookieStore; } @NonNull public static EhClient getEhClient(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mEhClient == null) { application.mEhClient = new EhClient(application); } return application.mEhClient; } @NonNull public static OkHttpClient getOkHttpClient(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mOkHttpClient == null) { application.mOkHttpClient = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS) .cookieJar(getEhCookieStore(application)) .build(); } return application.mOkHttpClient; } @NonNull public static BitmapHelper getBitmapHelper(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mBitmapHelper == null) { application.mBitmapHelper = new BitmapHelper(); } return application.mBitmapHelper; } private static int getMemoryCacheMaxSize(Context context) { final ActivityManager activityManager = (ActivityManager) context. getSystemService(Context.ACTIVITY_SERVICE); return Math.min(20 * 1024 * 1024, Math.round(0.2f * activityManager.getMemoryClass() * 1024 * 1024)); } @NonNull public static Conaco getConaco(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mConaco == null) { Conaco.Builder builder = new Conaco.Builder<>(); builder.hasMemoryCache = true; builder.memoryCacheMaxSize = getMemoryCacheMaxSize(context); builder.hasDiskCache = true; builder.diskCacheDir = new File(context.getCacheDir(), "thumb"); builder.diskCacheMaxSize = 80 * 1024 * 1024; // 80MB builder.okHttpClient = getOkHttpClient(context); builder.objectHelper = getBitmapHelper(context); builder.debug = DEBUG_CONACO; application.mConaco = builder.build(); } return application.mConaco; } @NonNull public static LruCache getGalleryDetailCache(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mGalleryDetailCache == null) { // Max size 25, 3 min timeout application.mGalleryDetailCache = new LruCache<>(25); } return application.mGalleryDetailCache; } @NonNull public static SimpleDiskCache getSpiderInfoCache(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (null == application.mSpiderInfoCache) { application.mSpiderInfoCache = new SimpleDiskCache( new File(context.getCacheDir(), "spider_info"), 5 * 1024 * 1024); // 5M } return application.mSpiderInfoCache; } @NonNull public static DownloadManager getDownloadManager(@NonNull Context context) { EhApplication application = ((EhApplication) context.getApplicationContext()); if (application.mDownloadManager == null) { application.mDownloadManager = new DownloadManager(application); } return application.mDownloadManager; } private boolean handleException(Throwable ex) { if (ex == null) { return false; } try { ex.printStackTrace(); Crash.saveCrashInfo2File(this, ex); return true; } catch (Throwable tr) { return false; } } @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { mDefaultHandler.uncaughtException(thread, ex); } android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } @NonNull public static String getDeveloperEmail() { return "ehviewersu$gmail.com".replace('$', '@'); } public void registerActivity(Activity activity) { mActivityList.add(activity); } public void unregisterActivity(Activity activity) { mActivityList.remove(activity); } @Nullable public Activity getTopActivity() { if (!mActivityList.isEmpty()) { return mActivityList.get(mActivityList.size() - 1); } else { return null; } } }