/*
* Copyright (C) 2013 - 2016 Alexander "Evisceration" Martinz
*
* 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.namelessrom.devicecontrol;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.Vibrator;
import android.support.annotation.WorkerThread;
import android.support.v7.app.AppCompatDelegate;
import android.util.Log;
import org.namelessrom.devicecontrol.models.DeviceConfig;
import org.namelessrom.devicecontrol.utils.CustomTabsHelper;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import at.amartinz.execution.ShellManager;
import at.amartinz.universaldebug.UniversalDebug;
import at.amartinz.universaldebug.fabric.FabricConfig;
import at.amartinz.universaldebug.fabric.trees.CrashlyticsComponent;
import at.amartinz.universaldebug.trees.BaseTree;
import at.amartinz.universaldebug.trees.LogComponent;
import at.amartinz.universaldebug.trees.VibrationComponent;
import at.amartinz.universaldebug.trees.WriterComponent;
import io.paperdb.Paper;
import timber.log.Timber;
// XXX: DO NOT USE ROOT HERE! NEVER!
public class App extends android.app.Application {
public static final Handler HANDLER = new Handler(Looper.getMainLooper());
private static final int APP_VERSION = 1;
private static App sInstance;
private static boolean enableDebug = BuildConfig.DEBUG;
private CustomTabsHelper customTabsHelper;
private PowerManager powerManager;
private Vibrator vibrator;
public static App get() {
return App.sInstance;
}
public static App get(Context context) {
return ((App) context.getApplicationContext());
}
public CustomTabsHelper getCustomTabsHelper() {
if (customTabsHelper == null) {
customTabsHelper = new CustomTabsHelper(this);
}
return customTabsHelper;
}
public PowerManager getPowerManager() {
if (powerManager == null) {
powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
}
return powerManager;
}
public Vibrator getVibrator() {
if (vibrator == null) {
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}
return vibrator;
}
@Override public void onCreate() {
super.onCreate();
if (App.sInstance != null) {
return;
}
App.sInstance = this;
final UniversalDebug universalDebug = new UniversalDebug(this)
.withDebug(BuildConfig.DEBUG)
.withTimber(true)
.withDebugTree(buildDebugTree())
.withProductionTree(buildProductionTree());
if (!enableDebug) {
final FabricConfig fabricConfig = new FabricConfig(universalDebug)
.withAnswers()
.withCrashlytics();
universalDebug.withExtension(fabricConfig);
}
universalDebug.install();
ShellManager.enableDebug(App.enableDebug);
Paper.init(this);
setupThemeMode();
AsyncTask.execute(new Runnable() {
@Override public void run() {
setupEverythingAsync();
}
});
}
public static void setupThemeMode() {
final DeviceConfig deviceConfig = DeviceConfig.get();
switch (deviceConfig.themeMode) {
case DeviceConfig.THEME_AUTO: {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
break;
}
case DeviceConfig.THEME_DAY: {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
break;
}
default:
case DeviceConfig.THEME_NIGHT: {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
break;
}
}
}
@WorkerThread private void setupEverythingAsync() {
Timber.d("Enable debug: %s", App.enableDebug);
final String basePath = getFilesDirectory();
final String[] dirList = new String[]{ basePath + DeviceConstants.DC_LOG_DIR };
for (final String s : dirList) {
final File dir = new File(s);
if (!dir.exists()) {
Timber.v("setupDirectories: creating %s -> %s", s, dir.mkdirs());
}
}
handleAppUpgrades();
if (App.enableDebug) {
final int gmsVersion = getResources().getInteger(R.integer.google_play_services_version);
Timber.v("Google Play Services -> %s", gmsVersion);
}
}
private void handleAppUpgrades() {
boolean needsUpgrade = false;
final DeviceConfig deviceConfig = DeviceConfig.get();
if (deviceConfig.appVersion < 1) {
needsUpgrade = true;
final File externalCache = new File(getExternalCacheDir(), "bitmapCache");
clearDirectory(externalCache);
final File internalCacheOld = new File(getFilesDir(), "bitmapCache");
clearDirectory(internalCacheOld);
final File internalCache = new File(getCacheDir(), "bitmapCache");
clearDirectory(internalCache);
}
if (needsUpgrade) {
deviceConfig.appVersion = APP_VERSION;
deviceConfig.save();
}
}
@SuppressWarnings("ResultOfMethodCallIgnored") private void clearDirectory(File directory) {
if (directory.exists()) {
final File[] cacheFiles = directory.listFiles();
if (cacheFiles != null) {
for (final File cacheFile : cacheFiles) {
cacheFile.delete();
}
}
directory.delete();
}
}
@SuppressLint("SdCardPath") public String getFilesDirectory() {
final File tmp = getFilesDir();
if (tmp != null && tmp.isDirectory()) {
return tmp.getPath();
} else {
return "/data/data/" + getPackageName();
}
}
public String[] getStringArray(final int resId) {
return getResources().getStringArray(resId);
}
private BaseTree buildDebugTree() {
return buildTree(true);
}
private BaseTree buildProductionTree() {
return buildTree(false);
}
private BaseTree buildTree(boolean isDebug) {
final HashSet<Integer> priorityFilter = new HashSet<>();
// if we are in release mode, remove all log calls except ERROR and WARN
if (!isDebug) {
priorityFilter.addAll(Arrays.asList(Log.ASSERT, Log.DEBUG, Log.INFO, Log.VERBOSE));
}
final BaseTree baseTree = new BaseTree(this, priorityFilter);
final LogComponent logComponent = new LogComponent(baseTree);
baseTree.addComponent(logComponent);
if (isDebug) {
final VibrationComponent vibrationComponent = new VibrationComponent(baseTree);
// only vibrate on error logs
final HashSet<Integer> vibrationFilter = new HashSet<>(
Arrays.asList(Log.ASSERT, Log.DEBUG, Log.INFO, Log.VERBOSE, Log.WARN));
vibrationComponent.setPriorityFilterSet(vibrationFilter);
baseTree.addComponent(vibrationComponent);
final WriterComponent writerComponent = new WriterComponent(baseTree, getExternalCacheDir());
// only vibrate on error and warning logs
final HashSet<Integer> writerFilter = new HashSet<>(
Arrays.asList(Log.ASSERT, Log.DEBUG, Log.INFO, Log.VERBOSE, Log.WARN));
writerComponent.setPriorityFilterSet(writerFilter);
baseTree.addComponent(writerComponent);
}
final CrashlyticsComponent crashlyticsComponent = new CrashlyticsComponent(baseTree);
baseTree.addComponent(crashlyticsComponent);
return baseTree;
}
}