Remove masquerade patches
authorLuK1337 <priv.luk@gmail.com>
Sun, 26 Feb 2017 00:22:17 +0000 (01:22 +0100)
committerLuK1337 <priv.luk@gmail.com>
Sun, 26 Feb 2017 00:22:17 +0000 (01:22 +0100)
patch.sh
patches/packages/apps/masquerade/0001-Rewrite-Masquerade-for-UID-system-ops-1-3.patch [deleted file]
patches/packages/apps/masquerade/0002-Finalize-masquerade-rootless-functionality-with-Subs.patch [deleted file]
patches/packages/apps/masquerade/0003-Release-23-Introduce-the-rootless-solution-for-Masqu.patch [deleted file]

index fd437027949a37414e4db143119d6d4f43f4f8a8..26b33dbe75b84731a01e38e7e474d2a1ca7ab926 100755 (executable)
--- a/patch.sh
+++ b/patch.sh
@@ -5,7 +5,6 @@ REPOSITORIES=(
     'packages/apps/Settings'
     'packages/apps/ExactCalculator'
     'packages/apps/PhoneCommon'
-    'packages/apps/masquerade'
     'build'
     'system/core'
     'system/sepolicy'
diff --git a/patches/packages/apps/masquerade/0001-Rewrite-Masquerade-for-UID-system-ops-1-3.patch b/patches/packages/apps/masquerade/0001-Rewrite-Masquerade-for-UID-system-ops-1-3.patch
deleted file mode 100644 (file)
index 1789e66..0000000
+++ /dev/null
@@ -1,2284 +0,0 @@
-From 2b7192e30c8a93b716def9fc564e90867e0f96f3 Mon Sep 17 00:00:00 2001
-From: bigrushdog <randall.rushing@gmail.com>
-Date: Wed, 14 Dec 2016 01:06:32 -0800
-Subject: [PATCH 1/3] Rewrite Masquerade for UID system ops [1/3]
-
-Allow Substratum to offload a handful of functions
-to system to support rootless operation
-
-Credit @Surge1223 for cleaning up restartUI function
-https://github.com/VelvetProject/packages_apps_masquerade/commit/3484db3dda1e7bf7e3f6fda049b903968f1506e7
-
-Change-Id: Ie379fc81e5b80550e044df59c80a60b4890c340c
----
- app/src/main/AndroidManifest.xml                   |   33 +-
- .../substratum/activities/LoaderActivity.java      |   17 -
- .../substratum/receivers/BootReceiver.java         |   13 +
- .../UninstallReceiver.java}                        |   11 +-
- .../substratum/services/BootDetector.java          |   15 -
- .../masquerade/substratum/services/JobService.java | 1005 ++++++++++++++++++++
- .../masquerade/substratum/services/MasqDemo.java   |  137 +++
- .../java/masquerade/substratum/util/Helper.java    |  113 ---
- .../substratum/util/IconPackApplicator.java        |  136 ---
- .../substratum/util/ReadOverlaysFile.java          |   46 -
- .../main/java/masquerade/substratum/util/Root.java |   83 --
- .../masquerade/substratum/util/Uninstaller.java    |  107 ---
- .../java/masquerade/substratum/utils/IOUtils.java  |  170 ++++
- .../masquerade/substratum/utils/SoundUtils.java    |  210 ++++
- 14 files changed, 1555 insertions(+), 541 deletions(-)
- delete mode 100644 app/src/main/java/masquerade/substratum/activities/LoaderActivity.java
- create mode 100644 app/src/main/java/masquerade/substratum/receivers/BootReceiver.java
- rename app/src/main/java/masquerade/substratum/{services/UninstallDetector.java => receivers/UninstallReceiver.java} (87%)
- delete mode 100644 app/src/main/java/masquerade/substratum/services/BootDetector.java
- create mode 100644 app/src/main/java/masquerade/substratum/services/JobService.java
- create mode 100644 app/src/main/java/masquerade/substratum/services/MasqDemo.java
- delete mode 100644 app/src/main/java/masquerade/substratum/util/Helper.java
- delete mode 100644 app/src/main/java/masquerade/substratum/util/IconPackApplicator.java
- delete mode 100644 app/src/main/java/masquerade/substratum/util/ReadOverlaysFile.java
- delete mode 100644 app/src/main/java/masquerade/substratum/util/Root.java
- delete mode 100644 app/src/main/java/masquerade/substratum/util/Uninstaller.java
- create mode 100644 app/src/main/java/masquerade/substratum/utils/IOUtils.java
- create mode 100644 app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-
-diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
-index aaffdf2..13db0f9 100644
---- a/app/src/main/AndroidManifest.xml
-+++ b/app/src/main/AndroidManifest.xml
-@@ -1,12 +1,20 @@
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-           package="masquerade.substratum"
--          android:versionCode="20"
--          android:versionName="twenty - procyon">
-+          android:versionCode="21"
-+          android:versionName="twentyone - something"
-+          coreApp="true"
-+          android:sharedUserId="android.uid.system">
-     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
-     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
-+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-+    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
-+    <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
-+    <uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
-+    <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"/>
-+    <uses-permission android:name="android.permission.MODIFY_OVERLAYS"/>
-     <application
-         android:allowBackup="true"
-@@ -14,30 +22,19 @@
-         android:label="@string/app_name"
-         android:supportsRtl="true"
-         android:theme="@style/AppTheme">
--        <receiver android:name="masquerade.substratum.services.BootDetector">
-+        <receiver android:name=".receivers.BootReceiver">
-             <intent-filter>
-                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
-             </intent-filter>
-         </receiver>
--        <receiver android:name=".services.UninstallDetector">
-+        <receiver android:name=".receivers.UninstallReceiver">
-             <intent-filter>
-                 <action android:name="android.intent.action.PACKAGE_REMOVED"/>
-                 <data android:scheme="package"/>
-             </intent-filter>
-         </receiver>
--        <receiver android:name=".util.Helper">
--            <intent-filter>
--                <action android:name="masquerade.substratum.COMMANDS"/>
--            </intent-filter>
--        </receiver>
--
--        <activity android:name="masquerade.substratum.activities.LoaderActivity">
--            <intent-filter>
--                <action android:name="android.intent.action.MAIN"/>
--                <action android:name="masquerade.substratum.INITIALIZE"/>
--
--                <category android:name="android.intent.category.DEFAULT"/>
--            </intent-filter>
--        </activity>
-+        <service android:name=".services.JobService"
-+            android:exported="true"
-+            android:permission="android.permission.MODIFY_OVERLAYS" />
-     </application>
- </manifest>
-diff --git a/app/src/main/java/masquerade/substratum/activities/LoaderActivity.java b/app/src/main/java/masquerade/substratum/activities/LoaderActivity.java
-deleted file mode 100644
-index 3af5ec3..0000000
---- a/app/src/main/java/masquerade/substratum/activities/LoaderActivity.java
-+++ /dev/null
-@@ -1,17 +0,0 @@
--package masquerade.substratum.activities;
--
--import android.app.Activity;
--import android.os.Bundle;
--import android.util.Log;
--
--import masquerade.substratum.util.Root;
--
--public class LoaderActivity extends Activity {
--    @Override
--    protected void onCreate(Bundle savedInstanceState) {
--        super.onCreate(savedInstanceState);
--        Log.d("Masquerade", "Masquerade is now securing superuser permissions!");
--        Root.requestRootAccess();
--        finish();
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/receivers/BootReceiver.java b/app/src/main/java/masquerade/substratum/receivers/BootReceiver.java
-new file mode 100644
-index 0000000..ebc0c8b
---- /dev/null
-+++ b/app/src/main/java/masquerade/substratum/receivers/BootReceiver.java
-@@ -0,0 +1,13 @@
-+package masquerade.substratum.receivers;
-+
-+import android.content.BroadcastReceiver;
-+import android.content.Context;
-+import android.content.Intent;
-+
-+
-+public class BootReceiver extends BroadcastReceiver {
-+    @Override
-+    public void onReceive(Context context, Intent intent) {
-+        // do something
-+    }
-+}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/services/UninstallDetector.java b/app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java
-similarity index 87%
-rename from app/src/main/java/masquerade/substratum/services/UninstallDetector.java
-rename to app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java
-index 7af387b..b377e27 100644
---- a/app/src/main/java/masquerade/substratum/services/UninstallDetector.java
-+++ b/app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java
-@@ -1,4 +1,4 @@
--package masquerade.substratum.services;
-+package masquerade.substratum.receivers;
- import android.content.BroadcastReceiver;
- import android.content.Context;
-@@ -11,20 +11,18 @@ import android.util.Log;
- import java.util.ArrayList;
- import java.util.List;
--import masquerade.substratum.util.ReadOverlaysFile;
--import masquerade.substratum.util.Root;
--public class UninstallDetector extends BroadcastReceiver {
-+public class UninstallReceiver extends BroadcastReceiver {
-     @Override
-     public void onReceive(Context context, Intent intent) {
-         if ("android.intent.action.PACKAGE_REMOVED".equals(intent.getAction())) {
-             Uri packageName = intent.getData();
-             if (packageName.toString().substring(8).equals("projekt.substratum")) {
--                new performUninstalls().execute("");
-+//                new performUninstalls().execute("");
-             }
-         }
-     }
--
-+/*
-     public class performUninstalls extends AsyncTask<String, Integer, String> {
-         @Override
-         protected String doInBackground(String... sUrl) {
-@@ -45,4 +43,5 @@ public class UninstallDetector extends BroadcastReceiver {
-             return null;
-         }
-     }
-+    */
- }
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/services/BootDetector.java b/app/src/main/java/masquerade/substratum/services/BootDetector.java
-deleted file mode 100644
-index 3981487..0000000
---- a/app/src/main/java/masquerade/substratum/services/BootDetector.java
-+++ /dev/null
-@@ -1,15 +0,0 @@
--package masquerade.substratum.services;
--
--import android.content.BroadcastReceiver;
--import android.content.Context;
--import android.content.Intent;
--
--import masquerade.substratum.util.Helper;
--
--public class BootDetector extends BroadcastReceiver {
--    @Override
--    public void onReceive(Context context, Intent intent) {
--        Intent pushIntent = new Intent(context, Helper.class);
--        context.startService(pushIntent);
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/services/JobService.java b/app/src/main/java/masquerade/substratum/services/JobService.java
-new file mode 100644
-index 0000000..3c1b859
---- /dev/null
-+++ b/app/src/main/java/masquerade/substratum/services/JobService.java
-@@ -0,0 +1,1005 @@
-+
-+package masquerade.substratum.services;
-+
-+import android.app.ActivityManager;
-+import android.app.ActivityManagerNative;
-+import android.app.PendingIntent;
-+import android.app.Service;
-+import android.content.BroadcastReceiver;
-+import android.content.ComponentName;
-+import android.content.Context;
-+import android.content.IIntentReceiver;
-+import android.content.IIntentSender;
-+import android.content.Intent;
-+import android.content.IntentFilter;
-+import android.content.IntentSender;
-+import android.content.om.IOverlayManager;
-+import android.content.om.OverlayInfo;
-+import android.content.pm.IPackageInstallObserver2;
-+import android.content.pm.IPackageManager;
-+import android.content.pm.PackageInstaller;
-+import android.content.pm.PackageManager;
-+import android.content.pm.PackageManager.NameNotFoundException;
-+import android.content.res.AssetManager;
-+import android.content.res.Configuration;
-+import android.graphics.Typeface;
-+import android.media.RingtoneManager;
-+import android.os.Binder;
-+import android.os.Bundle;
-+import android.os.FileUtils;
-+import android.os.Handler;
-+import android.os.HandlerThread;
-+import android.os.IBinder;
-+import android.os.Looper;
-+import android.os.Message;
-+import android.os.Process;
-+import android.os.RemoteException;
-+import android.os.ServiceManager;
-+import android.os.SystemProperties;
-+import android.os.UserHandle;
-+import android.provider.Settings;
-+import android.text.TextUtils;
-+import android.util.Log;
-+
-+import java.io.BufferedInputStream;
-+import java.io.BufferedOutputStream;
-+import java.io.File;
-+import java.io.FileInputStream;
-+import java.io.FileNotFoundException;
-+import java.io.FileOutputStream;
-+import java.io.IOException;
-+import java.io.InputStream;
-+import java.io.OutputStream;
-+import java.lang.reflect.Method;
-+import java.util.ArrayList;
-+import java.util.List;
-+import java.util.Locale;
-+import java.util.concurrent.SynchronousQueue;
-+import java.util.concurrent.TimeUnit;
-+import java.util.zip.ZipEntry;
-+import java.util.zip.ZipInputStream;
-+
-+import masquerade.substratum.utils.IOUtils;
-+import masquerade.substratum.utils.SoundUtils;
-+
-+import com.android.internal.statusbar.IStatusBarService;
-+
-+public class JobService extends Service {
-+    private static final String TAG = JobService.class.getSimpleName();
-+    private static final boolean DEBUG = true;
-+
-+    private static final String MASQUERADE_TOKEN = "masquerade_token";
-+    private static final String SUBSTRATUM_PACKAGE = "projekt.substratum";
-+    private static final String[] AUTHORIZED_CALLERS = new String[] {
-+            SUBSTRATUM_PACKAGE,
-+            "masquerade.substratum"
-+    };
-+
-+    public static final String INTENT_STATUS_CHANGED = "masquerade.substratum.STATUS_CHANGED";
-+
-+    public static final String PRIMARY_COMMAND_KEY = "primary_command_key";
-+    public static final String JOB_TIME_KEY = "job_time_key";
-+    public static final String INSTALL_LIST_KEY = "install_list";
-+    public static final String UNINSTALL_LIST_KEY = "uninstall_list";
-+    public static final String WITH_RESTART_UI_KEY = "with_restart_ui";
-+    public static final String BOOTANIMATION_FILE_NAME = "bootanimation_file_name";
-+    public static final String FONTS_PID = "fonts_pid";
-+    public static final String FONTS_FILENAME = "fonts_filename";
-+    public static final String AUDIO_PID = "audio_pid";
-+    public static final String AUDIO_FILENAME = "audio_filename";
-+    public static final String COMMAND_VALUE_JOB_COMPLETE = "job_complete";
-+    public static final String COMMAND_VALUE_INSTALL = "install";
-+    public static final String COMMAND_VALUE_UNINSTALL = "uninstall";
-+    public static final String COMMAND_VALUE_RESTART_UI = "restart_ui";
-+    public static final String COMMAND_VALUE_CONFIGURATION_SHIM = "configuration_shim";
-+    public static final String COMMAND_VALUE_BOOTANIMATION = "bootanimation";
-+    public static final String COMMAND_VALUE_FONTS = "fonts";
-+    public static final String COMMAND_VALUE_AUDIO = "audio";
-+
-+    private static IOverlayManager mOMS;
-+    private static IPackageManager mPM;
-+
-+    private HandlerThread mWorker;
-+    private JobHandler mJobHandler;
-+    private MainHandler mMainHandler;
-+    private final List<Runnable> mJobQueue = new ArrayList<>(0);
-+    private long mLastJobTime;
-+
-+    @Override
-+    public void onCreate() {
-+        mWorker = new HandlerThread("BackgroundWorker", Process.THREAD_PRIORITY_BACKGROUND);
-+        mWorker.start();
-+        mJobHandler = new JobHandler(mWorker.getLooper());
-+        mMainHandler = new MainHandler(Looper.getMainLooper());
-+    }
-+
-+    @Override
-+    public int onStartCommand(Intent intent, int flags, int startId) {
-+        // verify identity
-+        if (!isCallerAuthorized(intent)) {
-+            log("caller not authorized, aborting");
-+            return START_NOT_STICKY;
-+        }
-+
-+        // one job at a time please
-+        // if (isProcessing()) {
-+        // log("Got start command while still processing last job, aborting");
-+        // return START_NOT_STICKY;
-+        // }
-+        // filter out duplicate intents
-+        long jobTime = intent.getLongExtra(JOB_TIME_KEY, 1);
-+        if (jobTime == 1 || jobTime == mLastJobTime) {
-+            log("got empty jobtime or duplicate job time, aborting");
-+            return START_NOT_STICKY;
-+        }
-+        mLastJobTime = jobTime;
-+
-+        // must have a primary command
-+        String command = intent.getStringExtra(PRIMARY_COMMAND_KEY);
-+        if (TextUtils.isEmpty(command)) {
-+            log("Got empty primary command, aborting");
-+            return START_NOT_STICKY;
-+        }
-+
-+        // queue up the job
-+
-+        List<Runnable> jobs_to_add = new ArrayList<>(0);
-+
-+        log("Starting job with primary command " + command + " With job time " + jobTime);
-+        if (TextUtils.equals(command, COMMAND_VALUE_INSTALL)) {
-+            List<String> paths = intent.getStringArrayListExtra(INSTALL_LIST_KEY);
-+            for (String path : paths) {
-+                jobs_to_add.add(new Installer(path));
-+            }
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_UNINSTALL)) {
-+            List<String> packages = intent.getStringArrayListExtra(UNINSTALL_LIST_KEY);
-+            for (String _package : packages) {
-+                jobs_to_add.add(new Remover(_package));
-+            }
-+            if (intent.getBooleanExtra(WITH_RESTART_UI_KEY, false)) {
-+                jobs_to_add.add(new UiResetJob());
-+            }
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_RESTART_UI)) {
-+            jobs_to_add.add(new UiResetJob());
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_CONFIGURATION_SHIM)) {
-+            jobs_to_add.add(new LocaleChanger(getApplicationContext(), mMainHandler));
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_BOOTANIMATION)) {
-+            String fileName = intent.getStringExtra(BOOTANIMATION_FILE_NAME);
-+            if (TextUtils.isEmpty(fileName)) {
-+                jobs_to_add.add(new BootAnimationJob(true));
-+            } else {
-+                jobs_to_add.add(new BootAnimationJob(fileName));
-+            }
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_FONTS)) {
-+            String pid = intent.getStringExtra(FONTS_PID);
-+            String fileName = intent.getStringExtra(FONTS_FILENAME);
-+            jobs_to_add.add(new FontsJob(pid, fileName));
-+            jobs_to_add.add(new UiResetJob());
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_AUDIO)) {
-+            String pid = intent.getStringExtra(AUDIO_PID);
-+            String fileName = intent.getStringExtra(AUDIO_FILENAME);
-+            jobs_to_add.add(new SoundsJob(pid, fileName));
-+            jobs_to_add.add(new UiResetJob());
-+        }
-+
-+        if (jobs_to_add.size() > 0) {
-+            log("Adding new jobs to job queue");
-+            synchronized (mJobQueue) {
-+                mJobQueue.addAll(jobs_to_add);
-+            }
-+            if (!mJobHandler.hasMessages(JobHandler.MESSAGE_CHECK_QUEUE)) {
-+                mJobHandler.sendEmptyMessage(JobHandler.MESSAGE_CHECK_QUEUE);
-+            }
-+        }
-+
-+        return START_NOT_STICKY;
-+    }
-+
-+    @Override
-+    public IBinder onBind(Intent intent) {
-+        return null;
-+    }
-+
-+    @Override
-+    public void onDestroy() {
-+
-+    }
-+
-+    private boolean isProcessing() {
-+        return mJobQueue.size() > 0;
-+    }
-+
-+    private class LocalService extends Binder {
-+        public JobService getService() {
-+            return JobService.this;
-+        }
-+    }
-+
-+    private static IOverlayManager getOMS() {
-+        if (mOMS == null) {
-+            mOMS = IOverlayManager.Stub.asInterface(
-+                    ServiceManager.getService("overlay"));
-+        }
-+        return mOMS;
-+    }
-+
-+    private static IPackageManager getPM() {
-+        if (mPM == null) {
-+            mPM = IPackageManager.Stub.asInterface(
-+                    ServiceManager.getService("package"));
-+        }
-+        return mPM;
-+    }
-+
-+    private void install(String path, IPackageInstallObserver2 observer) {
-+        try {
-+            getPM().installPackageAsUser(path, observer, PackageManager.INSTALL_REPLACE_EXISTING,
-+                    null,
-+                    UserHandle.USER_SYSTEM);
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private void uninstall(String packageName) {
-+        try {
-+            final LocalIntentReceiver receiver = new LocalIntentReceiver();
-+            getPM().getPackageInstaller().uninstall(packageName, null /* callerPackageName */, 0,
-+                    receiver.getIntentSender(), UserHandle.USER_SYSTEM);
-+            final Intent result = receiver.getResult();
-+            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-+                    PackageInstaller.STATUS_FAILURE);
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private void disableOverlay(String packageName) {
-+        try {
-+            getOMS().setEnabled(packageName, false, UserHandle.USER_SYSTEM, false);
-+        } catch (RemoteException e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private boolean isOverlayEnabled(String packageName) {
-+        boolean enabled = false;
-+        try {
-+            OverlayInfo info = getOMS().getOverlayInfo(packageName, UserHandle.USER_ALL);
-+            enabled = info.isEnabled();
-+        } catch (RemoteException e) {
-+            e.printStackTrace();
-+        }
-+        return enabled;
-+    }
-+
-+    private void copyFonts(String pid, String zipFileName) {
-+        // prepare local cache dir for font package assembly
-+        log("Copy Fonts - Package ID = " + pid + " filename = " + zipFileName);
-+        File cacheDir = new File(getCacheDir(), "/FontCache/");
-+        if (cacheDir.exists()) {
-+            IOUtils.deleteRecursive(cacheDir);
-+        }
-+        cacheDir.mkdir();
-+
-+        // copy system fonts into our cache dir
-+        IOUtils.copyFolder("/system/fonts", cacheDir.getAbsolutePath());
-+
-+        // append zip to filename since it is probably removed
-+        // for list presentation
-+        if (!zipFileName.endsWith(".zip")) {
-+            zipFileName = zipFileName + ".zip";
-+        }
-+
-+        // copy target themed fonts zip to our cache dir
-+        Context themeContext = getAppContext(pid);
-+        AssetManager am = themeContext.getAssets();
-+        try {
-+            InputStream inputStream = am.open("fonts/" + zipFileName);
-+            OutputStream outputStream = new FileOutputStream(getCacheDir()
-+                    .getAbsolutePath() + "/FontCache/" + zipFileName);
-+            IOUtils.bufferedCopy(inputStream, outputStream);
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+
-+        // unzip new fonts and delete zip file, overwriting any system fonts
-+        File fontZip = new File(getCacheDir(), "/FontCache/" + zipFileName);
-+        IOUtils.unzip(fontZip.getAbsolutePath(), cacheDir.getAbsolutePath());
-+        fontZip.delete();
-+
-+        // check if theme zip included a fonts.xml. If not, Substratum
-+        // is kind enough to provide one for us in it's assets
-+        try {
-+            File testConfig = new File(getCacheDir(), "/FontCache/" + "fonts.xml");
-+            if (!testConfig.exists()) {
-+                Context subContext = getSubsContext();
-+                AssetManager subsAm = subContext.getAssets();
-+                InputStream inputStream = subsAm.open("fonts.xml");
-+                OutputStream outputStream = new FileOutputStream(testConfig);
-+                IOUtils.bufferedCopy(inputStream, outputStream);
-+            }
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+
-+        // prepare system theme fonts folder and copy new fonts folder from our cache
-+        IOUtils.deleteThemedFonts();
-+        IOUtils.createFontDirIfNotExists();
-+        IOUtils.copyFolder(cacheDir.getAbsolutePath(), IOUtils.SYSTEM_THEME_FONT_PATH);
-+
-+        // set permissions on font files and config xml
-+        File themeFonts = new File(IOUtils.SYSTEM_THEME_FONT_PATH);
-+        for (File f : themeFonts.listFiles()) {
-+            FileUtils.setPermissions(f,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
-+        }
-+
-+        // let system know it's time for a font change
-+        SystemProperties.set("sys.refresh_theme", "1");
-+        float fontSize = Float.valueOf(Settings.System.getString(
-+                getContentResolver(), Settings.System.FONT_SCALE));
-+        Settings.System.putString(getContentResolver(),
-+                Settings.System.FONT_SCALE, String.valueOf(fontSize + 0.0000001));
-+    }
-+
-+    private void clearFonts() {
-+        IOUtils.deleteThemedFonts();
-+        SystemProperties.set("sys.refresh_theme", "1");
-+        Typeface.recreateDefaults();
-+        float fontSize = Float.valueOf(Settings.System.getString(
-+                getContentResolver(), Settings.System.FONT_SCALE));
-+        Settings.System.putString(getContentResolver(),
-+                Settings.System.FONT_SCALE, String.valueOf(fontSize + 0.0000001));
-+    }
-+
-+    private void applyThemedSounds(String pid, String zipFileName) {
-+        // prepare local cache dir for font package assembly
-+        log("Copy sounds - Package ID = " + pid + " filename = " + zipFileName);
-+        File cacheDir = new File(getCacheDir(), "/SoundsCache/");
-+        if (cacheDir.exists()) {
-+            IOUtils.deleteRecursive(cacheDir);
-+        }
-+        cacheDir.mkdir();
-+
-+        // append zip to filename since it is probably removed
-+        // for list presentation
-+        if (!zipFileName.endsWith(".zip")) {
-+            zipFileName = zipFileName + ".zip";
-+        }
-+
-+        // copy target themed sounds zip to our cache dir
-+        Context themeContext = getAppContext(pid);
-+        AssetManager am = themeContext.getAssets();
-+        try {
-+            InputStream inputStream = am.open("audio/" + zipFileName);
-+            OutputStream outputStream = new FileOutputStream(getCacheDir()
-+                    .getAbsolutePath() + "/SoundsCache/" + zipFileName);
-+            IOUtils.bufferedCopy(inputStream, outputStream);
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+
-+        // unzip new sounds and delete zip file
-+        File soundsZip = new File(getCacheDir(), "/SoundsCache/" + zipFileName);
-+        IOUtils.unzip(soundsZip.getAbsolutePath(), cacheDir.getAbsolutePath());
-+        soundsZip.delete();
-+
-+        clearSounds(this);
-+        IOUtils.createAudioDirIfNotExists();
-+
-+        File uiSoundsCache = new File(getCacheDir(), "/SoundsCache/ui/");
-+        if (uiSoundsCache.exists() && uiSoundsCache.isDirectory()) {
-+            IOUtils.createUiSoundsDirIfNotExists();
-+            File effect_tick_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Effect_Tick.mp3");
-+            File effect_tick_ogg = new File(getCacheDir(), "/SoundsCache/ui/Effect_Tick.ogg");
-+            if (effect_tick_ogg.exists()) {
-+                IOUtils.bufferedCopy(effect_tick_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.ogg"));
-+                SoundUtils.setUIAudible(this, effect_tick_ogg, new File
-+                        ("/data/system/theme/audio/ui/Effect_Tick.ogg"), RingtoneManager
-+                        .TYPE_RINGTONE, "Effect_Tick");
-+            } else if (effect_tick_mp3.exists()) {
-+                IOUtils.bufferedCopy(effect_tick_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.mp3"));
-+                SoundUtils.setUIAudible(this, effect_tick_mp3, new File
-+                        ("/data/system/theme/audio/ui/Effect_Tick.mp3"), RingtoneManager
-+                        .TYPE_RINGTONE, "Effect_Tick");
-+            } else {
-+                SoundUtils.setDefaultUISounds(getContentResolver(), "lock_sound", "Lock.ogg");
-+            }
-+            File new_lock_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Lock.mp3");
-+            File new_lock_ogg = new File(getCacheDir(), "/SoundsCache/ui/Lock.ogg");
-+            if (new_lock_ogg.exists()) {
-+                IOUtils.bufferedCopy(new_lock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Lock.ogg"));
-+                SoundUtils.setUISounds(getContentResolver(), "lock_sound", "/data/system/theme/audio/ui/Lock.ogg");
-+            } else if (new_lock_mp3.exists()) {
-+                IOUtils.bufferedCopy(new_lock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Lock.mp3"));
-+                SoundUtils.setUISounds(getContentResolver(), "lock_sound", "/data/system/theme/audio/ui/Lock.mp3");
-+            } else {
-+                SoundUtils.setDefaultUISounds(getContentResolver(), "lock_sound", "Lock.ogg");
-+            }
-+            File new_unlock_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Unlock.mp3");
-+            File new_unlock_ogg = new File(getCacheDir(), "/SoundsCache/ui/Unlock.ogg");
-+            if (new_unlock_ogg.exists()) {
-+                IOUtils.bufferedCopy(new_unlock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Unlock.ogg"));
-+                SoundUtils.setUISounds(getContentResolver(), "unlock_sound", "/data/system/theme/audio/ui/Unlock.ogg");
-+            } else if (new_unlock_mp3.exists()) {
-+                IOUtils.bufferedCopy(new_unlock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Unlock.mp3"));
-+                SoundUtils.setUISounds(getContentResolver(), "unlock_sound", "/data/system/theme/audio/ui/Unlock.mp3");
-+            } else {
-+                SoundUtils.setDefaultUISounds(getContentResolver(), "unlock_sound", "Unlock.ogg");
-+            }
-+            File new_lowbattery_mp3 = new File(getCacheDir(), "/SoundsCache/ui/LowBattery.mp3");
-+            File new_lowbattery_ogg = new File(getCacheDir(), "/SoundsCache/ui/LowBattery.ogg");
-+            if (new_lowbattery_ogg.exists()) {
-+                IOUtils.bufferedCopy(new_lowbattery_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.ogg"));
-+                SoundUtils.setUISounds(getContentResolver(), "low_battery_sound", "/data/system/theme/audio/ui/LowBattery.ogg");
-+            } else if (new_lowbattery_mp3.exists()) {
-+                IOUtils.bufferedCopy(new_lowbattery_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.mp3"));
-+                SoundUtils.setUISounds(getContentResolver(), "low_battery_sound", "/data/system/theme/audio/ui/LowBattery.mp3");
-+            } else {
-+                SoundUtils.setDefaultUISounds(getContentResolver(), "low_battery_sound", "LowBattery.ogg");
-+            }
-+            File uiSounds = new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH);
-+            if (uiSounds.exists() && uiSounds.isDirectory()) {
-+                for (File f : uiSounds.listFiles()) {
-+                    FileUtils.setPermissions(f,
-+                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
-+                }
-+            }
-+        }
-+        File alarmCache = new File(getCacheDir(), "/SoundsCache/alarms/");
-+        if (alarmCache.exists() && alarmCache.isDirectory()) {
-+            IOUtils.createAlarmDirIfNotExists();
-+            File new_alarm_mp3 = new File(getCacheDir(), "/SoundsCache/alarms/alarm.mp3");
-+            File new_alarm_ogg = new File(getCacheDir(), "/SoundsCache/alarms/alarm.ogg");
-+            if (new_alarm_ogg.exists()) {
-+                IOUtils.bufferedCopy(new_alarm_ogg, new File(IOUtils.SYSTEM_THEME_ALARM_PATH + File.separator + "alarm.ogg"));
-+                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_alarm_metadata", "string", SUBSTRATUM_PACKAGE);
-+                SoundUtils.setAudible(this, new File("/data/system/theme/audio/alarms/alarm.ogg"),
-+                        new File(alarmCache.getAbsolutePath(), "alarm.ogg"),
-+                        RingtoneManager.TYPE_ALARM,
-+                        getSubsContext().getString(metaDataId));
-+            } else if (new_alarm_mp3.exists()) {
-+                IOUtils.bufferedCopy(new_alarm_mp3, new File(IOUtils.SYSTEM_THEME_ALARM_PATH + File.separator + "alarm.mp3"));
-+                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_alarm_metadata", "string", SUBSTRATUM_PACKAGE);
-+                SoundUtils.setAudible(this, new File("/data/system/theme/audio/alarms/alarm.mp3"),
-+                        new File(alarmCache.getAbsolutePath(), "alarm.mp3"),
-+                        RingtoneManager.TYPE_ALARM,
-+                        getSubsContext().getString(metaDataId));
-+            } else {
-+                SoundUtils.setDefaultAudible(this, RingtoneManager.TYPE_ALARM);
-+            }
-+            File alarms = new File(IOUtils.SYSTEM_THEME_ALARM_PATH);
-+            if (alarms.exists() && alarms.isDirectory()) {
-+                for (File f : alarms.listFiles()) {
-+                    FileUtils.setPermissions(f,
-+                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
-+                }
-+            }
-+        }
-+        File notifCache = new File(getCacheDir(), "/SoundsCache/notifications/");
-+        if (notifCache.exists() && notifCache.isDirectory()) {
-+            IOUtils.createNotificationDirIfNotExists();
-+            File new_notif_mp3 = new File(getCacheDir(), "/SoundsCache/notifications/notification.mp3");
-+            File new_notif_ogg = new File(getCacheDir(), "/SoundsCache/notifications/notification.ogg");
-+            if (new_notif_ogg.exists()) {
-+                IOUtils.bufferedCopy(new_notif_ogg, new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.ogg"));
-+                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_notification_metadata", "string", SUBSTRATUM_PACKAGE);
-+                SoundUtils.setAudible(this, new File("/data/system/theme/audio/notifications/notification.ogg"),
-+                        new File(notifCache.getAbsolutePath(), "notification.ogg"),
-+                        RingtoneManager.TYPE_NOTIFICATION,
-+                        getSubsContext().getString(metaDataId));
-+            } else if (new_notif_mp3.exists()) {
-+                IOUtils.bufferedCopy(new_notif_mp3, new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.mp3"));
-+                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_notification_metadata", "string", SUBSTRATUM_PACKAGE);
-+                SoundUtils.setAudible(this, new File("/data/system/theme/audio/notifications/notification.mp3"),
-+                        new File(notifCache.getAbsolutePath(), "notification.mp3"),
-+                        RingtoneManager.TYPE_NOTIFICATION,
-+                        getSubsContext().getString(metaDataId));
-+            } else {
-+                SoundUtils.setDefaultAudible(this, RingtoneManager.TYPE_NOTIFICATION);
-+            }
-+            File notifs = new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH);
-+            if (notifs.exists() && notifs.isDirectory()) {
-+                for (File f : notifs.listFiles()) {
-+                    FileUtils.setPermissions(f,
-+                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
-+                }
-+            }
-+        }
-+        File ringtoneCache = new File(getCacheDir(), "/SoundsCache/ringtones/");
-+        if (ringtoneCache.exists() && ringtoneCache.isDirectory()) {
-+            IOUtils.createRingtoneDirIfNotExists();
-+            File new_ring_mp3 = new File(getCacheDir(), "/SoundsCache/ringtones/ringtone.mp3");
-+            File new_ring_ogg = new File(getCacheDir(), "/SoundsCache/ringtones/ringtone.ogg");
-+            if (new_ring_ogg.exists()) {
-+                IOUtils.bufferedCopy(new_ring_ogg, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH + File.separator + "ringtone.ogg"));
-+                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_ringtone_metadata", "string", SUBSTRATUM_PACKAGE);
-+                SoundUtils.setAudible(this, new File("/data/system/theme/audio/ringtones/ringtone.ogg"),
-+                        new File(notifCache.getAbsolutePath(), "ringtone.ogg"),
-+                        RingtoneManager.TYPE_RINGTONE,
-+                        getSubsContext().getString(metaDataId));
-+            } else if (new_ring_mp3.exists()) {
-+                IOUtils.bufferedCopy(new_ring_mp3, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH + File.separator + "ringtone.mp3"));
-+                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_ringtone_metadata", "string", SUBSTRATUM_PACKAGE);
-+                SoundUtils.setAudible(this, new File("/data/system/theme/audio/ringtones/ringtone.mp3"),
-+                        new File(notifCache.getAbsolutePath(), "ringtone.mp3"),
-+                        RingtoneManager.TYPE_RINGTONE,
-+                        getSubsContext().getString(metaDataId));
-+            } else {
-+                SoundUtils.setDefaultAudible(this, RingtoneManager.TYPE_RINGTONE);
-+            }
-+            File rings = new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH);
-+            if (rings.exists() && rings.isDirectory()) {
-+                for (File f : rings.listFiles()) {
-+                    FileUtils.setPermissions(f,
-+                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
-+                }
-+            }
-+        }
-+    }
-+
-+    private void clearSounds(Context ctx) {
-+        IOUtils.deleteThemedAudio();
-+        SoundUtils.setDefaultAudible(JobService.this, RingtoneManager.TYPE_ALARM);
-+        SoundUtils.setDefaultAudible(JobService.this, RingtoneManager.TYPE_NOTIFICATION);
-+        SoundUtils.setDefaultAudible(JobService.this, RingtoneManager.TYPE_RINGTONE);
-+        SoundUtils.setDefaultUISounds(getContentResolver(), "lock_sound", "Lock.ogg");
-+        SoundUtils.setDefaultUISounds(getContentResolver(), "unlock_sound", "Unlock.ogg");
-+        SoundUtils.setDefaultUISounds(getContentResolver(), "low_battery_sound",
-+                "LowBattery.ogg");
-+    }
-+
-+    private void copyBootAnimation(String fileName) {
-+        try {
-+            clearBootAnimation();
-+            File source = new File(fileName);
-+            File dest = new File(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH);
-+            IOUtils.bufferedCopy(source, dest);
-+            source.delete();
-+            FileUtils.setPermissions(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private void clearBootAnimation() {
-+        try {
-+            File f = new File(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH);
-+            if (f.exists()) {
-+                f.delete();
-+            }
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private void restartUi() {
-+        try {
-+            ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
-+            Class ActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
-+            Method getDefault = ActivityManagerNative.getDeclaredMethod("getDefault", null);
-+            Object amn = getDefault.invoke(null, null);
-+            Method killApplicationProcess = amn.getClass().getDeclaredMethod("killApplicationProcess", String.class, int.class);
-+            stopService(new Intent().setComponent(new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")));
-+            am.killBackgroundProcesses("com.android.systemui");
-+            for (ActivityManager.RunningAppProcessInfo app : am.getRunningAppProcesses()) {
-+                if ("com.android.systemui".equals(app.processName)) {
-+                    killApplicationProcess.invoke(amn, app.processName, app.uid);
-+                    break;
-+                }
-+            }
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private void killPackage(String packageName) {
-+        try {
-+            ActivityManagerNative.getDefault().forceStopPackage(packageName,
-+                    UserHandle.USER_SYSTEM);
-+        } catch (RemoteException e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    private Context getSubsContext() {
-+        return getAppContext(SUBSTRATUM_PACKAGE);
-+    }
-+
-+    private Context getAppContext(String packageName) {
-+        Context ctx = null;
-+        try {
-+            ctx = getApplicationContext().createPackageContext(packageName,
-+                    Context.CONTEXT_IGNORE_SECURITY);
-+        } catch (NameNotFoundException e) {
-+            e.printStackTrace();
-+        }
-+        return ctx;
-+    }
-+
-+    public static void log(String msg) {
-+        if (DEBUG) {
-+            Log.e(TAG, msg);
-+        }
-+    }
-+
-+    private boolean isCallerAuthorized(Intent intent) {
-+        PendingIntent token = null;
-+        try {
-+            token = (PendingIntent) intent.getParcelableExtra(MASQUERADE_TOKEN);
-+        } catch (Exception e) {
-+            log("Attempt to start serivce without a token, unauthorized");
-+        }
-+        if (token == null) {
-+            return false;
-+        }
-+        // SECOND: we got a token, validate originating package
-+        // if not in our whitelist, return null
-+        String callingPackage = token.getCreatorPackage();
-+        boolean isValidPackage = false;
-+        for (int i = 0; i < AUTHORIZED_CALLERS.length; i++) {
-+            if (TextUtils.equals(callingPackage, AUTHORIZED_CALLERS[i])) {
-+                log(callingPackage
-+                        + " is an authorized calling package, next validate calling package perms");
-+                isValidPackage = true;
-+                break;
-+            }
-+        }
-+        if (!isValidPackage) {
-+            log(callingPackage + " is not an authorized calling package");
-+            return false;
-+        }
-+        return true;
-+    }
-+
-+    private class MainHandler extends Handler {
-+        public static final int MSG_JOB_QUEUE_EMPTY = 1;
-+
-+        public MainHandler(Looper looper) {
-+            super(looper);
-+        }
-+
-+        @Override
-+        public void handleMessage(Message msg) {
-+            switch (msg.what) {
-+                case MSG_JOB_QUEUE_EMPTY:
-+                    Intent intent = new Intent(INTENT_STATUS_CHANGED);
-+                    intent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_JOB_COMPLETE);
-+                    sendBroadcastAsUser(intent, UserHandle.ALL);
-+                    break;
-+            }
-+        }
-+    }
-+
-+    private class JobHandler extends Handler {
-+        private static final int MESSAGE_CHECK_QUEUE = 1;
-+        private static final int MESSAGE_DEQUEUE = 2;
-+
-+        public JobHandler(Looper looper) {
-+            super(looper);
-+        }
-+
-+        @Override
-+        public void handleMessage(Message msg) {
-+            switch (msg.what) {
-+                case MESSAGE_CHECK_QUEUE:
-+                    Runnable job;
-+                    synchronized (mJobQueue) {
-+                        job = mJobQueue.get(0);
-+                    }
-+                    if (job != null) {
-+                        job.run();
-+                    }
-+                    break;
-+                case MESSAGE_DEQUEUE:
-+                    Runnable toRemove = (Runnable) msg.obj;
-+                    synchronized (mJobQueue) {
-+                        mJobQueue.remove(toRemove);
-+                        if (mJobQueue.size() > 0) {
-+                            this.sendEmptyMessage(MESSAGE_CHECK_QUEUE);
-+                        } else {
-+                            log("Job queue empty! All done");
-+                            mMainHandler.sendEmptyMessage(MainHandler.MSG_JOB_QUEUE_EMPTY);
-+                        }
-+                    }
-+                    break;
-+                default:
-+                    log("Unknown message " + msg.what);
-+                    break;
-+            }
-+        }
-+    }
-+
-+    private class StopPackageJob implements Runnable {
-+        String mPackage;
-+
-+        public void StopPackageJob(String _package) {
-+            mPackage = _package;
-+        }
-+
-+        @Override
-+        public void run() {
-+            killPackage(mPackage);
-+            log("Killed package " + mPackage);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    StopPackageJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class UiResetJob implements Runnable {
-+        @Override
-+        public void run() {
-+            restartUi();
-+            log("Restarting SystemUI...");
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    UiResetJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class FontsJob implements Runnable {
-+        boolean mClear;
-+        String mPid;
-+        String mFileName;
-+
-+        public FontsJob(String pid, String fileName) {
-+            if (pid == null) {
-+                mClear = true;
-+            } else {
-+                mPid = pid;
-+                mFileName = fileName;
-+            }
-+        }
-+
-+        @Override
-+        public void run() {
-+            if (mClear) {
-+                log("Resetting system font");
-+                clearFonts();
-+            } else {
-+                log("Setting theme font");
-+                copyFonts(mPid, mFileName);
-+            }
-+            Intent intent = new Intent(INTENT_STATUS_CHANGED);
-+            intent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_FONTS);
-+            sendBroadcastAsUser(intent, UserHandle.ALL);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    FontsJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class SoundsJob implements Runnable {
-+        boolean mClear;
-+        String mPid;
-+        String mFileName;
-+
-+        public SoundsJob(String pid, String fileName) {
-+            if (pid == null) {
-+                mClear = true;
-+            } else {
-+                mPid = pid;
-+                mFileName = fileName;
-+            }
-+        }
-+
-+        @Override
-+        public void run() {
-+            if (mClear) {
-+                log("Resetting system sounds");
-+                clearSounds(JobService.this);
-+            } else {
-+                log("Setting theme sounds");
-+                applyThemedSounds(mPid, mFileName);
-+            }
-+            Intent intent = new Intent(INTENT_STATUS_CHANGED);
-+            intent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_AUDIO);
-+            sendBroadcastAsUser(intent, UserHandle.ALL);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    SoundsJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class BootAnimationJob implements Runnable {
-+        String mFileName;
-+        final boolean mClear;
-+
-+        public BootAnimationJob(boolean clear) {
-+            mClear = true;
-+        }
-+
-+        public BootAnimationJob(String fileName) {
-+            mFileName = fileName;
-+            mClear = false;
-+        }
-+
-+        @Override
-+        public void run() {
-+            if (mClear) {
-+                log("Resetting system boot animation");
-+                clearBootAnimation();
-+            } else {
-+                log("Setting themed boot animation");
-+                copyBootAnimation(mFileName);
-+            }
-+            Intent intent = new Intent(INTENT_STATUS_CHANGED);
-+            intent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_BOOTANIMATION);
-+            sendBroadcastAsUser(intent, UserHandle.ALL);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    BootAnimationJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class Installer implements Runnable, IPackageInstallObserver2 {
-+        String mPath;
-+
-+        public Installer(String path) {
-+            mPath = path;
-+        }
-+
-+        @Override
-+        public IBinder asBinder() {
-+            return null;
-+        }
-+
-+        @Override
-+        public void onUserActionRequired(Intent intent) throws RemoteException {
-+            log("Installer - user action required callback with " + mPath);
-+        }
-+
-+        @Override
-+        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
-+                Bundle extras) throws RemoteException {
-+            log("Installer - successfully installed " + basePackageName + " from " + mPath);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE, Installer.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("Installer - installing " + mPath);
-+            install(mPath, this);
-+        }
-+    }
-+
-+    private class Remover implements Runnable {
-+        String mPackage;
-+
-+        public Remover(String _package) {
-+            mPackage = _package;
-+        }
-+
-+        @Override
-+        public void run() {
-+            if (isOverlayEnabled(mPackage)) {
-+                log("Remover - disabling overlay for " + mPackage);
-+                disableOverlay(mPackage);
-+            }
-+            log("Remover - uninstalling " + mPackage);
-+            uninstall(mPackage);
-+        }
-+    }
-+
-+    private class LocaleChanger extends BroadcastReceiver implements Runnable {
-+        private boolean mIsRegistered;
-+        private boolean mDoRestore;
-+        private Context mContext;
-+        private Handler mHandler;
-+        private Locale mCurrentLocale;
-+
-+        public LocaleChanger(Context context, Handler mainHandler) {
-+            mContext = context;
-+            mHandler = mainHandler;
-+        }
-+
-+        @Override
-+        public void run() {
-+            Intent i = new Intent(Intent.ACTION_MAIN);
-+            i.addCategory(Intent.CATEGORY_HOME);
-+            mContext.startActivity(i);
-+            mHandler.postDelayed(new Runnable() {
-+                @Override
-+                public void run() {
-+                    spoofLocale();
-+                }
-+            }, 500);
-+        }
-+
-+        private void register() {
-+            if (!mIsRegistered) {
-+                IntentFilter filter = new IntentFilter();
-+                filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-+                mContext.registerReceiver(LocaleChanger.this, filter);
-+                mIsRegistered = true;
-+            }
-+        }
-+
-+        private void unregister() {
-+            if (mIsRegistered) {
-+                mContext.unregisterReceiver(LocaleChanger.this);
-+                mIsRegistered = false;
-+            }
-+        }
-+
-+        private void spoofLocale() {
-+            Configuration config;
-+            log("LocaleChanger - spoofing locale for configuation change shim");
-+            try {
-+                register();
-+                config = ActivityManagerNative.getDefault().getConfiguration();
-+                mCurrentLocale = config.locale;
-+                Locale toSpoof = Locale.JAPAN;
-+                if (mCurrentLocale == Locale.JAPAN) {
-+                    toSpoof = Locale.CHINA;
-+                }
-+                config.setLocale(toSpoof);
-+                config.userSetLocale = true;
-+                ActivityManagerNative.getDefault().updateConfiguration(config);
-+            } catch (RemoteException e) {
-+                e.printStackTrace();
-+                return;
-+            }
-+        }
-+
-+        private void restoreLocale() {
-+            Configuration config;
-+            log("LocaleChanger - restoring original locale for configuation change shim");
-+            try {
-+                unregister();
-+                config = ActivityManagerNative.getDefault().getConfiguration();
-+                config.setLocale(mCurrentLocale);
-+                config.userSetLocale = true;
-+                ActivityManagerNative.getDefault().updateConfiguration(config);
-+            } catch (RemoteException e) {
-+                e.printStackTrace();
-+                return;
-+            }
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    LocaleChanger.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+
-+        @Override
-+        public void onReceive(Context context, Intent intent) {
-+            mHandler.postDelayed(new Runnable() {
-+                @Override
-+                public void run() {
-+                    restoreLocale();
-+                }
-+            }, 500);
-+        }
-+    }
-+
-+    private static class LocalIntentReceiver {
-+        private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
-+
-+        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
-+            @Override
-+            public void send(int code, Intent intent, String resolvedType,
-+                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-+                try {
-+                    mResult.offer(intent, 5, TimeUnit.SECONDS);
-+                } catch (InterruptedException e) {
-+                    throw new RuntimeException(e);
-+                }
-+            }
-+        };
-+
-+        public IntentSender getIntentSender() {
-+            return new IntentSender((IIntentSender) mLocalSender);
-+        }
-+
-+        public Intent getResult() {
-+            try {
-+                return mResult.take();
-+            } catch (InterruptedException e) {
-+                throw new RuntimeException(e);
-+            }
-+        }
-+    }
-+}
-diff --git a/app/src/main/java/masquerade/substratum/services/MasqDemo.java b/app/src/main/java/masquerade/substratum/services/MasqDemo.java
-new file mode 100644
-index 0000000..b00d6e0
---- /dev/null
-+++ b/app/src/main/java/masquerade/substratum/services/MasqDemo.java
-@@ -0,0 +1,137 @@
-+
-+package masquerade.substratum.services;
-+
-+import java.util.ArrayList;
-+import java.util.List;
-+
-+import android.app.PendingIntent;
-+import android.content.BroadcastReceiver;
-+import android.content.Context;
-+import android.content.Intent;
-+import android.text.TextUtils;
-+
-+public class MasqDemo {
-+    public static final String MASQUERADE_TOKEN = "masquerade_token";
-+    public static final String PRIMARY_COMMAND_KEY = "primary_command_key";
-+    public static final String JOB_TIME_KEY = "job_time_key";
-+    public static final String INSTALL_LIST_KEY = "install_list";
-+    public static final String UNINSTALL_LIST_KEY = "uninstall_list";
-+    public static final String WITH_RESTART_UI_KEY = "with_restart_ui";
-+    public static final String BOOTANIMATION_PID_KEY = "bootanimation_pid";
-+    public static final String BOOTANIMATION_FILE_NAME = "bootanimation_file_name";
-+    public static final String FONTS_PID = "fonts_pid";
-+    public static final String FONTS_FILENAME = "fonts_filename";
-+    public static final String AUDIO_PID = "audio_pid";
-+    public static final String AUDIO_FILENAME = "audio_filename";
-+    public static final String COMMAND_VALUE_INSTALL = "install";
-+    public static final String COMMAND_VALUE_UNINSTALL = "uninstall";
-+    public static final String COMMAND_VALUE_RESTART_UI = "restart_ui";
-+    public static final String COMMAND_VALUE_CONFIGURATION_SHIM = "configuration_shim";
-+    public static final String COMMAND_VALUE_BOOTANIMATION = "bootanimation";
-+    public static final String COMMAND_VALUE_FONTS = "fonts";
-+    public static final String COMMAND_VALUE_AUDIO = "audio";
-+    public static final String INTENT_STATUS_CHANGED = "masquerade.substratum.STATUS_CHANGED";
-+    public static final String COMMAND_VALUE_JOB_COMPLETE = "job_complete";
-+
-+    class MasqReceiver extends BroadcastReceiver {
-+        @Override
-+        public void onReceive(Context context, Intent intent) {
-+            if (TextUtils.equals(intent.getAction(), INTENT_STATUS_CHANGED)) {
-+                String command = intent.getStringExtra(PRIMARY_COMMAND_KEY);
-+                if (TextUtils.equals(command, COMMAND_VALUE_FONTS)) {
-+                    // update ui, dismiss progress dialog, etc
-+                } else if (TextUtils.equals(command, COMMAND_VALUE_BOOTANIMATION)) {
-+
-+                } else if (TextUtils.equals(command, COMMAND_VALUE_AUDIO)) {
-+
-+                } else if (TextUtils.equals(command, COMMAND_VALUE_JOB_COMPLETE)) {
-+
-+                }
-+            }
-+        }
-+    }
-+
-+    // demo code for building a base intent for JobService commands
-+    public static Intent getMasqIntent(Context ctx) {
-+        Intent intent = new Intent();
-+        intent.setClassName("masquerade.substratum", "masquerade.substratum.services.JobService");
-+        // Credit StackOverflow http://stackoverflow.com/a/28132098
-+        // Use dummy PendingIntent for service to validate caller at onBind
-+        PendingIntent pending = PendingIntent.getActivity(ctx, 0, new Intent(), 0);
-+        intent.putExtra(MASQUERADE_TOKEN, pending);
-+        intent.putExtra(JOB_TIME_KEY, System.currentTimeMillis());
-+        return intent;
-+    }
-+
-+    public static void install(Context context, ArrayList<String> overlay_apks) {
-+        // populate list however
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_INSTALL);
-+        masqIntent.putExtra(INSTALL_LIST_KEY, overlay_apks);
-+        context.startService(masqIntent);
-+    }
-+
-+    public static void uninstall(Context context, ArrayList<String> packages_to_remove) {
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_UNINSTALL);
-+        masqIntent.putExtra(UNINSTALL_LIST_KEY, packages_to_remove);
-+        // only need to set if true, will restart SystemUI when done processing packages
-+        masqIntent.putExtra(WITH_RESTART_UI_KEY, true);
-+        context.startService(masqIntent);
-+    }
-+
-+    public static void restartSystemUI(Context context) {
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_RESTART_UI);
-+        context.startService(masqIntent);
-+    }
-+
-+    public static void configurationChangeShim(Context context) {
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_CONFIGURATION_SHIM);
-+        context.startService(masqIntent);
-+    }
-+    
-+    public static void clearThemedBootAnimation(Context context) {
-+        applyThemedBootAnimation(context, null);
-+    }
-+    
-+    public static void applyThemedBootAnimation(Context context, String fileName) {
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_BOOTANIMATION);
-+        if (fileName != null) {
-+            masqIntent.putExtra(BOOTANIMATION_FILE_NAME, fileName);
-+        } else {
-+            // nothing. to reset to stock, just don't add PID and FILE
-+        }
-+        context.startService(masqIntent);
-+    }
-+    
-+    public static void clearThemedFont(Context context) {
-+        applyThemedFont(context, null, null);
-+    }
-+
-+    public static void applyThemedFont(Context context, String pid, String fileName) {
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_FONTS);
-+        if (pid != null) {
-+            masqIntent.putExtra(FONTS_PID, pid);
-+            masqIntent.putExtra(FONTS_FILENAME, fileName);
-+        }
-+        context.startService(masqIntent);
-+    }
-+
-+    public static void clearThemedSounds(Context context) {
-+        applyThemedSounds(context, null, null);
-+    }
-+
-+    public static void applyThemedSounds(Context context, String pid, String fileName) {
-+        Intent masqIntent = getMasqIntent(context);
-+        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_AUDIO);
-+        if (pid != null) {
-+            masqIntent.putExtra(AUDIO_PID, pid);
-+            masqIntent.putExtra(AUDIO_FILENAME, fileName);
-+        }
-+        context.startService(masqIntent);
-+    }
-+}
-diff --git a/app/src/main/java/masquerade/substratum/util/Helper.java b/app/src/main/java/masquerade/substratum/util/Helper.java
-deleted file mode 100644
-index cccf493..0000000
---- a/app/src/main/java/masquerade/substratum/util/Helper.java
-+++ /dev/null
-@@ -1,113 +0,0 @@
--package masquerade.substratum.util;
--
--import android.app.PendingIntent;
--import android.content.BroadcastReceiver;
--import android.content.Context;
--import android.content.Intent;
--import android.os.Handler;
--import android.text.TextUtils;
--import android.util.Log;
--
--public class Helper extends BroadcastReceiver {
--
--    private static final String SUBSTRATUM_PACKAGE = "projekt.substratum";
--    private static final String MASQUERADE_TOKEN = "masquerade_token";
--    private static final String[] AUTHORIZED_CALLERS = new String[]{
--            SUBSTRATUM_PACKAGE,
--            "masquerade.substratum"
--    };
--
--    @Override
--    public void onReceive(Context context, Intent intent) {
--        if (!isCallerAuthorized(intent)) {
--            Log.d("Masquerade", "Caller not authorized");
--            return;
--        }
--        Log.d("Masquerade",
--                "BroadcastReceiver has accepted Substratum's commands and is running now...");
--        Root.requestRootAccess();
--
--        if (intent.getStringExtra("substratum-check") != null) {
--            if (intent.getStringExtra("substratum-check").equals("masquerade-ball")) {
--                Intent runCommand = new Intent();
--                runCommand.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
--                runCommand.setAction("projekt.substratum.MASQUERADE_BALL");
--                runCommand.putExtra("substratum-check", "masquerade-ball");
--                context.sendBroadcast(runCommand);
--                Log.d("Masquerade", "BroadcastReceiver was triggered to check for system " +
--                        "integrity and service activation.");
--            }
--        } else if (intent.getStringArrayListExtra("pm-uninstall") != null) {
--            new Uninstaller().uninstall(intent, "pm-uninstall", false,
--                    intent.getBooleanExtra("restart_systemui", false));
--        } else if (intent.getStringArrayListExtra("pm-uninstall-specific") != null) {
--            new Uninstaller().uninstall(intent, "pm-uninstall-specific", true,
--                    intent.getBooleanExtra("restart_systemui", false));
--        } else if (intent.getStringArrayListExtra("icon-handler") != null) {
--            String icon_pack_name = intent.getStringArrayListExtra("icon-handler").get(0);
--            String main_delay = intent.getStringArrayListExtra("icon-handler").get(2);
--            String delay_one = intent.getStringArrayListExtra("icon-handler").get(3);
--            String delay_two = intent.getStringArrayListExtra("icon-handler").get(4);
--            final String bypass = intent.getStringArrayListExtra("icon-handler").get(5);
--            if (bypass == null) {
--                if (intent.getStringArrayListExtra("icon-handler").get(1).contains("pm") ||
--                        intent.getStringArrayListExtra("icon-handler").get(1).contains("om") ||
--                        intent.getStringArrayListExtra("icon-handler").get(1).contains("overlay")) {
--                    Log.d("Masquerade", "Running command: \"" +
--                            intent.getStringArrayListExtra("icon-handler").get(1) + "\"");
--                    Root.runCommand(intent.getStringArrayListExtra("icon-handler").get(1));
--                }
--            }
--            final Context mContext = context;
--            final String icon_pack = icon_pack_name;
--            final String delay_one_time = delay_one;
--            final String delay_two_time = delay_two;
--            final Handler handle = new Handler();
--            handle.postDelayed(new Runnable() {
--                @Override
--                public void run() {
--                    new IconPackApplicator().apply(
--                            mContext, icon_pack, delay_one_time, delay_two_time, bypass == null);
--                }
--            }, Integer.parseInt(main_delay));
--        } else if (intent.getStringExtra("om-commands") != null) {
--            if (intent.getStringExtra("om-commands").contains("pm") ||
--                    intent.getStringExtra("om-commands").contains("om") ||
--                    intent.getStringExtra("om-commands").contains("overlay")) {
--                Log.d("Masquerade", "Running command: \"" +
--                        intent.getStringExtra("om-commands") + "\"");
--                Root.runCommand(intent.getStringExtra("om-commands"));
--            }
--        }
--    }
--
--    private boolean isCallerAuthorized(Intent intent) {
--        PendingIntent token = null;
--        try {
--            token = intent.getParcelableExtra(MASQUERADE_TOKEN);
--        } catch (Exception e) {
--            Log.d("Masquerade", "Attempt to start service without a token, unauthorized");
--        }
--        if (token == null) {
--            return false;
--        }
--        // SECOND: we got a token, validate originating package
--        // if not in our white list, return null
--        String callingPackage = token.getCreatorPackage();
--        boolean isValidPackage = false;
--        for (int i = 0; i < AUTHORIZED_CALLERS.length; i++) {
--            if (TextUtils.equals(callingPackage, AUTHORIZED_CALLERS[i])) {
--                Log.d("Masquerade", callingPackage
--                        + " is an authorized calling package, next validate calling package perms");
--                isValidPackage = true;
--                break;
--            }
--        }
--        if (!isValidPackage) {
--            Log.d("Masquerade", callingPackage
--                    + " is not an authorized calling package");
--            return false;
--        }
--        return true;
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/util/IconPackApplicator.java b/app/src/main/java/masquerade/substratum/util/IconPackApplicator.java
-deleted file mode 100644
-index fb5d682..0000000
---- a/app/src/main/java/masquerade/substratum/util/IconPackApplicator.java
-+++ /dev/null
-@@ -1,136 +0,0 @@
--package masquerade.substratum.util;
--
--import android.content.Context;
--import android.content.Intent;
--import android.content.pm.PackageManager;
--import android.content.res.Resources;
--import android.os.Handler;
--import android.util.Log;
--import android.widget.Toast;
--
--import java.util.Locale;
--
--class IconPackApplicator {
--
--    private Context mContext;
--    private String iconPackName;
--    private String toast_text = null;
--    private int delayOne, delayTwo;
--    private Boolean bypass;
--
--    private static void grantPermission(final String packager, final String permission) {
--        Root.runCommand("pm grant " + packager + " " + permission);
--    }
--
--    void apply(Context mContext, String iconPackName, String delayOne, String delayTwo,
--               Boolean bypass) {
--        this.mContext = mContext;
--        this.iconPackName = iconPackName;
--        this.delayOne = Integer.parseInt(delayOne);
--        this.delayTwo = Integer.parseInt(delayTwo);
--        this.bypass = bypass;
--        iconInjector();
--    }
--
--    private boolean checkChangeConfigurationPermissions() {
--        String permission = "android.permission.CHANGE_CONFIGURATION";
--        int res = mContext.checkCallingOrSelfPermission(permission);
--        return (res == PackageManager.PERMISSION_GRANTED);
--    }
--
--    private void iconInjector() {
--        if (!checkChangeConfigurationPermissions()) {
--            Log.e("Masquerade", "Masquerade was not granted " +
--                    "CHANGE_CONFIGURATION permissions, allowing now...");
--            grantPermission("masquerade.substratum",
--                    "android.permission.CHANGE_CONFIGURATION");
--        } else {
--            Log.d("Masquerade",
--                    "Masquerade already granted CHANGE_CONFIGURATION permissions!");
--        }
--        try {
--            // Move home, since this is where we want our config code affected
--            Intent i = new Intent(Intent.ACTION_MAIN);
--            i.addCategory(Intent.CATEGORY_HOME);
--            mContext.startActivity(i);
--
--            // Take a fragment of memory to remember what the user's default config is
--            final Locale current_locale = mContext.getResources().getConfiguration().locale;
--            Locale to_be_changed = Locale.JAPAN;
--            // There are definitely Japanese locale users using our app, so we should take
--            // account for these people and switch to Chinese for 2 seconds.
--            if (current_locale == Locale.JAPAN) {
--                to_be_changed = Locale.CHINA;
--            }
--            final Locale changer = to_be_changed;
--
--            // Reflect back to framework and cause the language to change, we need this!
--            Class<?> activityManagerNative = Class.forName("android.app.ActivityManagerNative");
--            final Object am = activityManagerNative.getMethod("getDefault").invoke
--                    (activityManagerNative);
--            final Object config = am.getClass().getMethod("getConfiguration").invoke(am);
--
--            // Sniff Substratum's Resources
--            try {
--                Context otherContext = mContext.createPackageContext("projekt.substratum", 0);
--                Resources resources = otherContext.getResources();
--                if (bypass) {
--                    int toast = resources.getIdentifier("studio_applied_toast", "string",
--                            "projekt.substratum");
--                    toast_text = String.format(resources.getString(toast), iconPackName);
--                } else {
--                    int toast = resources.getIdentifier("studio_configuration_changed", "string",
--                            "projekt.substratum");
--                    toast_text = resources.getString(toast);
--                }
--            } catch (Exception e) {
--                // Suppress warning
--            }
--
--            // First window refresh to kick the change on the home screen
--            final Handler handle = new Handler();
--            handle.postDelayed(new Runnable() {
--                @Override
--                public void run() {
--                    try {
--                        config.getClass().getDeclaredField(
--                                "locale").set(config, changer);
--                        config.getClass().getDeclaredField(
--                                "userSetLocale").setBoolean(config, true);
--
--                        am.getClass().getMethod("updateConfiguration",
--                                android.content.res.Configuration.class).invoke(am, config);
--
--                        // Change the locale back to pre-icon pack application
--                        final Handler handler = new Handler();
--                        handler.postDelayed(new Runnable() {
--                            @Override
--                            public void run() {
--                                try {
--                                    config.getClass().getDeclaredField("locale").set(
--                                            config, current_locale);
--                                    config.getClass().getDeclaredField("userSetLocale")
--                                            .setBoolean(config, true);
--
--                                    am.getClass().getMethod("updateConfiguration",
--                                            android.content.res.Configuration
--                                                    .class).invoke(am, config);
--
--                                    if (toast_text != null)
--                                        Toast.makeText(
--                                                mContext, toast_text, Toast.LENGTH_SHORT).show();
--                                } catch (Exception e) {
--                                    // Suppress warning
--                                }
--                            }
--                        }, delayTwo); // 2 second delay for Home refresh
--                    } catch (Exception e) {
--                        // Suppress warning
--                    }
--                }
--            }, delayOne); // 1 second delay for Home refresh
--        } catch (Exception e) {
--            e.printStackTrace();
--        }
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/util/ReadOverlaysFile.java b/app/src/main/java/masquerade/substratum/util/ReadOverlaysFile.java
-deleted file mode 100644
-index 2909ea9..0000000
---- a/app/src/main/java/masquerade/substratum/util/ReadOverlaysFile.java
-+++ /dev/null
-@@ -1,46 +0,0 @@
--package masquerade.substratum.util;
--
--import android.os.Environment;
--
--import java.io.BufferedReader;
--import java.io.File;
--import java.io.FileReader;
--import java.io.IOException;
--import java.util.ArrayList;
--import java.util.List;
--
--public class ReadOverlaysFile {
--
--    public static List<String> main(String argv[]) {
--
--        File current_overlays = new File(Environment
--                .getExternalStorageDirectory().getAbsolutePath() +
--                "/.substratum/current_overlays.xml");
--        if (current_overlays.exists()) {
--            Root.runCommand("rm " + Environment
--                    .getExternalStorageDirectory().getAbsolutePath() +
--                    "/.substratum/current_overlays.xml");
--        }
--        Root.runCommand("cp /data/system/overlays.xml " +
--                Environment
--                        .getExternalStorageDirectory().getAbsolutePath() +
--                "/.substratum/current_overlays.xml");
--
--        File file = new File(argv[0]);
--        int state_count = Integer.parseInt(argv[1]);
--
--        List<String> list = new ArrayList<>();
--
--        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
--            for (String line; (line = br.readLine()) != null; ) {
--                if (line.contains("state=\"" + state_count + "\"")) {
--                    String[] split = line.substring(21).split("\\s+");
--                    list.add(split[0].substring(1, split[0].length() - 1));
--                }
--            }
--        } catch (IOException ioe) {
--            // Exception
--        }
--        return list;
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/util/Root.java b/app/src/main/java/masquerade/substratum/util/Root.java
-deleted file mode 100644
-index 7c80720..0000000
---- a/app/src/main/java/masquerade/substratum/util/Root.java
-+++ /dev/null
-@@ -1,83 +0,0 @@
--package masquerade.substratum.util;
--
--import java.io.BufferedReader;
--import java.io.BufferedWriter;
--import java.io.IOException;
--import java.io.InputStreamReader;
--import java.io.OutputStreamWriter;
--
--public class Root {
--
--    private static SU su;
--
--    public static boolean requestRootAccess() {
--        SU su = getSU();
--        su.runCommand("echo /testRoot/");
--        return !su.denied;
--    }
--
--    public static String runCommand(String command) {
--        return getSU().runCommand(command);
--    }
--
--    private static SU getSU() {
--        if (su == null) su = new SU();
--        else if (su.closed || su.denied) su = new SU();
--        return su;
--    }
--
--    private static class SU {
--
--        private Process process;
--        private BufferedWriter bufferedWriter;
--        private BufferedReader bufferedReader;
--        private boolean closed;
--        private boolean denied;
--        private boolean firstTry;
--
--        SU() {
--            try {
--                firstTry = true;
--                process = Runtime.getRuntime().exec("su");
--                bufferedWriter = new BufferedWriter(new OutputStreamWriter(process
--                        .getOutputStream()));
--                bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream
--                        ()));
--            } catch (IOException e) {
--                denied = true;
--                closed = true;
--            }
--        }
--
--        synchronized String runCommand(final String command) {
--            try {
--                StringBuilder sb = new StringBuilder();
--                String callback = "/shellCallback/";
--                bufferedWriter.write(command + "\necho " + callback + "\n");
--                bufferedWriter.flush();
--
--                int i;
--                char[] buffer = new char[256];
--                while (true) {
--                    sb.append(buffer, 0, bufferedReader.read(buffer));
--                    if ((i = sb.indexOf(callback)) > -1) {
--                        sb.delete(i, i + callback.length());
--                        break;
--                    }
--                }
--                firstTry = false;
--                return sb.toString().trim();
--            } catch (IOException e) {
--                closed = true;
--                e.printStackTrace();
--                if (firstTry) denied = true;
--            } catch (ArrayIndexOutOfBoundsException e) {
--                denied = true;
--            } catch (Exception e) {
--                e.printStackTrace();
--                denied = true;
--            }
--            return null;
--        }
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/util/Uninstaller.java b/app/src/main/java/masquerade/substratum/util/Uninstaller.java
-deleted file mode 100644
-index 4b1b056..0000000
---- a/app/src/main/java/masquerade/substratum/util/Uninstaller.java
-+++ /dev/null
-@@ -1,107 +0,0 @@
--package masquerade.substratum.util;
--
--import android.content.Intent;
--import android.os.AsyncTask;
--import android.os.Environment;
--import android.util.Log;
--
--import java.util.ArrayList;
--import java.util.List;
--
--class Uninstaller {
--
--    private Intent mIntent;
--    private String uninstallString;
--    private boolean specific;
--    private boolean restartSystemUI;
--
--    void uninstall(Intent mIntent, String uninstallString,
--                   boolean specific, boolean restartSystemUI) {
--        this.mIntent = mIntent;
--        this.uninstallString = uninstallString;
--        this.specific = specific;
--        this.restartSystemUI = restartSystemUI;
--        new UninstallAsync().execute("");
--    }
--
--    private class UninstallAsync extends AsyncTask<String, Integer, String> {
--
--        @Override
--        protected String doInBackground(String... sUrl) {
--            uninstall_handler(mIntent, uninstallString, specific, restartSystemUI);
--            return null;
--        }
--
--        private void uninstall_handler(Intent intent, String inheritor,
--                                       boolean specific, boolean restartSystemUI) {
--            try {
--                String final_commands_disable = "";
--                String final_commands_uninstall = "";
--
--                Root.runCommand(
--                        "pm grant masquerade.substratum android.permission.READ_EXTERNAL_STORAGE");
--                Root.runCommand(
--                        "pm grant masquerade.substratum android.permission.WRITE_EXTERNAL_STORAGE");
--
--                ArrayList<String> packages_to_uninstall =
--                        new ArrayList<>(intent.getStringArrayListExtra(inheritor));
--                String[] state5initial = {Environment.getExternalStorageDirectory()
--                        .getAbsolutePath() +
--                        "/.substratum/current_overlays.xml", "5"};
--                List<String> state5overlays = ReadOverlaysFile.main(state5initial);
--
--                for (int i = 0; i < packages_to_uninstall.size(); i++) {
--                    String current = packages_to_uninstall.get(i);
--
--                    Log.d("Masquerade", "Intent received to purge referendum package file \"" +
--                            current + "\"");
--                    if (state5overlays.contains(packages_to_uninstall.get(i))) {
--                        Log.d("Masquerade", "Package file \"" + current +
--                                "\" requires an overlay disable prior to uninstall...");
--                        if (final_commands_disable.length() == 0) {
--                            final_commands_disable = "om disable " + current;
--                        } else {
--                            final_commands_disable = final_commands_disable + " " + current;
--                        }
--
--                        if (final_commands_uninstall.length() == 0) {
--                            final_commands_uninstall = "pm uninstall " + current;
--                        } else {
--                            final_commands_uninstall = final_commands_uninstall +
--                                    " && pm uninstall " + current;
--                        }
--                    } else {
--                        Log.d("Masquerade", "\"" + current +
--                                "\" has been redirected to the package manager in " +
--                                "preparations of removal...");
--                        Root.runCommand("pm uninstall " + current);
--                    }
--                }
--
--                if (final_commands_disable.length() > 0) {
--                    Log.d("Masquerade", "Disable commands: " + final_commands_disable);
--                    Root.runCommand(final_commands_disable);
--                }
--                if (final_commands_uninstall.length() > 0) {
--                    Log.d("Masquerade", "Uninstall commands: " + final_commands_uninstall);
--                    Root.runCommand(final_commands_uninstall);
--                }
--
--                if (restartSystemUI) {
--                    Root.runCommand("pkill com.android.systemui");
--                }
--
--                if (!specific) {
--                    // Clear the resource idmapping files generated by OMS
--                    Log.d("Masquerade", "Cleaning up resource-cache directory...");
--                    Root.runCommand("rm /data/resource-cache/*");
--                    // Now clear the persistent overlays database
--                    Log.d("Masquerade", "Finalizing clean up of persistent overlays database...");
--                    Root.runCommand("rm -rf /data/system/overlays.xml");
--                }
--            } catch (Exception e) {
--                e.printStackTrace();
--            }
--        }
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/utils/IOUtils.java b/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-new file mode 100644
-index 0000000..092c58c
---- /dev/null
-+++ b/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-@@ -0,0 +1,170 @@
-+
-+package masquerade.substratum.utils;
-+
-+import java.io.BufferedInputStream;
-+import java.io.BufferedOutputStream;
-+import java.io.File;
-+import java.io.FileInputStream;
-+import java.io.FileNotFoundException;
-+import java.io.FileOutputStream;
-+import java.io.InputStream;
-+import java.io.OutputStream;
-+import java.util.zip.ZipEntry;
-+import java.util.zip.ZipInputStream;
-+
-+import android.os.FileUtils;
-+
-+public class IOUtils {
-+    public static final String SYSTEM_THEME_PATH = "/data/system/theme";
-+    public static final String SYSTEM_THEME_FONT_PATH = SYSTEM_THEME_PATH + File.separator
-+            + "fonts";
-+    public static final String SYSTEM_THEME_AUDIO_PATH = SYSTEM_THEME_PATH + File.separator
-+            + "audio";
-+    public static final String SYSTEM_THEME_RINGTONE_PATH = SYSTEM_THEME_AUDIO_PATH
-+            + File.separator + "ringtones";
-+    public static final String SYSTEM_THEME_NOTIFICATION_PATH = SYSTEM_THEME_AUDIO_PATH
-+            + File.separator + "notifications";
-+    public static final String SYSTEM_THEME_ALARM_PATH = SYSTEM_THEME_AUDIO_PATH
-+            + File.separator + "alarms";
-+    public static final String SYSTEM_THEME_UI_SOUNDS_PATH = SYSTEM_THEME_AUDIO_PATH
-+            + File.separator + "ui";
-+    public static final String SYSTEM_THEME_BOOTANIMATION_PATH = SYSTEM_THEME_PATH + File.separator
-+            + "bootanimation.zip";
-+
-+    public static boolean dirExists(String dirPath) {
-+        final File dir = new File(dirPath);
-+        return dir.exists() && dir.isDirectory();
-+    }
-+
-+    public static void createDirIfNotExists(String dirPath) {
-+        if (!dirExists(dirPath)) {
-+            File dir = new File(dirPath);
-+            if (dir.mkdir()) {
-+                FileUtils.setPermissions(dir, FileUtils.S_IRWXU |
-+                        FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
-+            }
-+        }
-+    }
-+
-+    public static void createFontDirIfNotExists() {
-+        createDirIfNotExists(SYSTEM_THEME_FONT_PATH);
-+    }
-+
-+    public static void createAudioDirIfNotExists() {
-+        createDirIfNotExists(SYSTEM_THEME_AUDIO_PATH);
-+    }
-+
-+    public static void createRingtoneDirIfNotExists() {
-+        createDirIfNotExists(SYSTEM_THEME_RINGTONE_PATH);
-+    }
-+
-+    public static void createNotificationDirIfNotExists() {
-+        createDirIfNotExists(SYSTEM_THEME_NOTIFICATION_PATH);
-+    }
-+
-+    public static void createAlarmDirIfNotExists() {
-+        createDirIfNotExists(SYSTEM_THEME_ALARM_PATH);
-+    }
-+
-+    public static void createUiSoundsDirIfNotExists() {
-+        createDirIfNotExists(SYSTEM_THEME_UI_SOUNDS_PATH);
-+    }
-+
-+    public static void deleteThemedFonts() {
-+        try {
-+            deleteRecursive(new File(SYSTEM_THEME_FONT_PATH));
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+    
-+    public static void deleteThemedAudio() {
-+        try {
-+            deleteRecursive(new File(SYSTEM_THEME_UI_SOUNDS_PATH));
-+            deleteRecursive(new File(SYSTEM_THEME_RINGTONE_PATH));
-+            deleteRecursive(new File(SYSTEM_THEME_NOTIFICATION_PATH));
-+            deleteRecursive(new File(SYSTEM_THEME_ALARM_PATH));
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    public static void copyFolder(String source, String dest) {
-+        File dir = new File(source);
-+        File[] files = dir.listFiles();
-+        for (File file : files) {
-+            try {
-+                String sourceFile = dir + File.separator + file.getName();
-+                String destinationFile = dest + File.separator + file.getName();
-+                bufferedCopy(new File(sourceFile), new File(destinationFile));
-+            } catch (Exception e) {
-+                e.printStackTrace();
-+            }
-+        }
-+    }
-+
-+    public static void unzip(String source, String destination) {
-+        try (ZipInputStream inputStream = new ZipInputStream(
-+                new BufferedInputStream(new FileInputStream(source)))) {
-+            ZipEntry zipEntry;
-+            int count;
-+            byte[] buffer = new byte[8192];
-+            while ((zipEntry = inputStream.getNextEntry()) != null) {
-+                File file = new File(destination, zipEntry.getName());
-+                File dir = zipEntry.isDirectory() ? file : file.getParentFile();
-+                if (!dir.isDirectory() && !dir.mkdirs())
-+                    throw new FileNotFoundException("Failed to ensure directory: " +
-+                            dir.getAbsolutePath());
-+                if (zipEntry.isDirectory())
-+                    continue;
-+                try (FileOutputStream outputStream = new FileOutputStream(file)) {
-+                    while ((count = inputStream.read(buffer)) != -1)
-+                        outputStream.write(buffer, 0, count);
-+                }
-+            }
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    public static void bufferedCopy(String source, String dest) {
-+        try {
-+            bufferedCopy(new FileInputStream(source), new FileOutputStream(dest));
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    public static void bufferedCopy(File source, File dest) {
-+        try {
-+            bufferedCopy(new FileInputStream(source), new FileOutputStream(dest));
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    public static void bufferedCopy(InputStream source, OutputStream dest) {
-+        try {
-+            BufferedInputStream in = new BufferedInputStream(source);
-+            BufferedOutputStream out = new BufferedOutputStream(dest);
-+            byte[] buff = new byte[32 * 1024];
-+            int len;
-+            while ((len = in.read(buff)) > 0) {
-+                out.write(buff, 0, len);
-+            }
-+            in.close();
-+            out.close();
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+        }
-+    }
-+
-+    public static void deleteRecursive(File fileOrDirectory) {
-+        if (fileOrDirectory.isDirectory())
-+            for (File child : fileOrDirectory.listFiles())
-+                deleteRecursive(child);
-+
-+        fileOrDirectory.delete();
-+    }
-+
-+}
-diff --git a/app/src/main/java/masquerade/substratum/utils/SoundUtils.java b/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-new file mode 100644
-index 0000000..72c6052
---- /dev/null
-+++ b/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-@@ -0,0 +1,210 @@
-+
-+package masquerade.substratum.utils;
-+
-+import java.io.File;
-+import java.util.Arrays;
-+
-+import android.content.ContentResolver;
-+import android.content.ContentValues;
-+import android.content.Context;
-+import android.database.Cursor;
-+import android.media.RingtoneManager;
-+import android.net.Uri;
-+import android.os.SystemProperties;
-+import android.os.UserHandle;
-+import android.provider.MediaStore;
-+import android.util.Log;
-+import android.provider.Settings;
-+
-+public class SoundUtils {
-+    private static final String SYSTEM_MEDIA_PATH = "/system/media/audio";
-+    private static final String SYSTEM_ALARMS_PATH =
-+            SYSTEM_MEDIA_PATH + File.separator + "alarms";
-+    private static final String SYSTEM_RINGTONES_PATH =
-+            SYSTEM_MEDIA_PATH + File.separator + "ringtones";
-+    private static final String SYSTEM_NOTIFICATIONS_PATH =
-+            SYSTEM_MEDIA_PATH + File.separator + "notifications";
-+    private static final String MEDIA_CONTENT_URI = "content://media/internal/audio/media";
-+
-+    public static void updateGlobalSettings(ContentResolver resolver, String uri, String val) {
-+        Settings.Global.putStringForUser(resolver, uri, val, UserHandle.USER_ALL);
-+    }
-+
-+    public static boolean setUISounds(ContentResolver resolver, String sound_name, String location) {
-+        if (allowedUISound(sound_name)) {
-+            updateGlobalSettings(resolver, sound_name, location);
-+            return true;
-+        }
-+        return false;
-+    }
-+
-+    public static void setDefaultUISounds(ContentResolver resolver, String sound_name,
-+            String sound_file) {
-+        updateGlobalSettings(resolver, sound_name, "/system/media/audio/ui/" + sound_file);
-+    }
-+
-+    // This string array contains all the SystemUI acceptable sound files
-+    public static Boolean allowedUISound(String targetValue) {
-+        String[] allowed_themable = {
-+                "lock_sound",
-+                "unlock_sound",
-+                "low_battery_sound"
-+        };
-+        return Arrays.asList(allowed_themable).contains(targetValue);
-+    }
-+
-+    public static String getDefaultAudiblePath(int type) {
-+        final String name;
-+        final String path;
-+        switch (type) {
-+            case RingtoneManager.TYPE_ALARM:
-+                name = SystemProperties.get("ro.config.alarm_alert");
-+                path = name != null ? SYSTEM_ALARMS_PATH + File.separator + name : null;
-+                break;
-+            case RingtoneManager.TYPE_NOTIFICATION:
-+                name = SystemProperties.get("ro.config.notification_sound");
-+                path = name != null ? SYSTEM_NOTIFICATIONS_PATH + File.separator + name : null;
-+                break;
-+            case RingtoneManager.TYPE_RINGTONE:
-+                name = SystemProperties.get("ro.config.ringtone");
-+                path = name != null ? SYSTEM_RINGTONES_PATH + File.separator + name : null;
-+                break;
-+            default:
-+                path = null;
-+                break;
-+        }
-+        return path;
-+    }
-+
-+    public static void clearAudibles(Context context, String audiblePath) {
-+        final File audibleDir = new File(audiblePath);
-+        if (audibleDir.exists() && audibleDir.isDirectory()) {
-+            String[] files = audibleDir.list();
-+            final ContentResolver resolver = context.getContentResolver();
-+            for (String s : files) {
-+                final String filePath = audiblePath + File.separator + s;
-+                Uri uri = MediaStore.Audio.Media.getContentUriForPath(filePath);
-+                resolver.delete(uri, MediaStore.MediaColumns.DATA + "=\""
-+                        + filePath + "\"", null);
-+                boolean deleted = (new File(filePath)).delete();
-+                if (deleted)
-+                    Log.e("SoundsHandler", "Database cleared");
-+            }
-+        }
-+    }
-+
-+    public static boolean setAudible(Context context, File ringtone, File ringtoneCache, int type,
-+            String name) {
-+        final String path = ringtone.getAbsolutePath();
-+        final String mimeType = name.endsWith(".ogg") ? "application/ogg" : "application/mp3";
-+        ContentValues values = new ContentValues();
-+        values.put(MediaStore.MediaColumns.DATA, path);
-+        values.put(MediaStore.MediaColumns.TITLE, name);
-+        values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
-+        values.put(MediaStore.MediaColumns.SIZE, ringtoneCache.length());
-+        values.put(MediaStore.Audio.Media.IS_RINGTONE, type == RingtoneManager.TYPE_RINGTONE);
-+        values.put(MediaStore.Audio.Media.IS_NOTIFICATION,
-+                type == RingtoneManager.TYPE_NOTIFICATION);
-+        values.put(MediaStore.Audio.Media.IS_ALARM, type == RingtoneManager.TYPE_ALARM);
-+        values.put(MediaStore.Audio.Media.IS_MUSIC, false);
-+
-+        Uri uri = MediaStore.Audio.Media.getContentUriForPath(path);
-+        Uri newUri = null;
-+        Cursor c = context.getContentResolver().query(uri,
-+                new String[] {
-+                    MediaStore.MediaColumns._ID
-+                },
-+                MediaStore.MediaColumns.DATA + "='" + path + "'",
-+                null, null);
-+        if (c != null && c.getCount() > 0) {
-+            c.moveToFirst();
-+            long id = c.getLong(0);
-+            c.close();
-+            newUri = Uri.withAppendedPath(Uri.parse(MEDIA_CONTENT_URI), "" + id);
-+            context.getContentResolver().update(uri, values,
-+                    MediaStore.MediaColumns._ID + "=" + id, null);
-+        }
-+        if (newUri == null)
-+            newUri = context.getContentResolver().insert(uri, values);
-+        try {
-+            RingtoneManager.setActualDefaultRingtoneUri(context, type, newUri);
-+        } catch (Exception e) {
-+            return false;
-+        }
-+        return true;
-+    }
-+
-+    public static boolean setUIAudible(Context context, File localized_ringtone,
-+            File ringtone_file, int type, String name) {
-+        final String path = ringtone_file.getAbsolutePath();
-+
-+        final String path_clone = "/system/media/audio/ui/" + name + ".ogg";
-+
-+        ContentValues values = new ContentValues();
-+        values.put(MediaStore.MediaColumns.DATA, path);
-+        values.put(MediaStore.MediaColumns.TITLE, name);
-+        values.put(MediaStore.MediaColumns.MIME_TYPE, "application/ogg");
-+        values.put(MediaStore.MediaColumns.SIZE, localized_ringtone.length());
-+        values.put(MediaStore.Audio.Media.IS_RINGTONE, false);
-+        values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
-+        values.put(MediaStore.Audio.Media.IS_ALARM, false);
-+        values.put(MediaStore.Audio.Media.IS_MUSIC, true);
-+
-+        Uri uri = MediaStore.Audio.Media.getContentUriForPath(path);
-+        Uri newUri = null;
-+        Cursor c = context.getContentResolver().query(uri,
-+                new String[] {
-+                    MediaStore.MediaColumns._ID
-+                },
-+                MediaStore.MediaColumns.DATA + "='" + path_clone + "'",
-+                null, null);
-+        if (c != null && c.getCount() > 0) {
-+            c.moveToFirst();
-+            long id = c.getLong(0);
-+            Log.e("ContentResolver", id + "");
-+            c.close();
-+            newUri = Uri.withAppendedPath(Uri.parse(MEDIA_CONTENT_URI), "" + id);
-+            try {
-+                context.getContentResolver().update(uri, values,
-+                        MediaStore.MediaColumns._ID + "=" + id, null);
-+            } catch (Exception e) {
-+                Log.d("SoundsHandler", "The content provider does not need to be updated.");
-+            }
-+        }
-+        if (newUri == null)
-+            newUri = context.getContentResolver().insert(uri, values);
-+        try {
-+            RingtoneManager.setActualDefaultRingtoneUri(context, type, newUri);
-+        } catch (Exception e) {
-+            e.printStackTrace();
-+            return false;
-+        }
-+        return true;
-+    }
-+
-+    public static boolean setDefaultAudible(Context context, int type) {
-+        final String audiblePath = getDefaultAudiblePath(type);
-+        if (audiblePath != null) {
-+            Uri uri = MediaStore.Audio.Media.getContentUriForPath(audiblePath);
-+            Cursor c = context.getContentResolver().query(uri,
-+                    new String[] {
-+                        MediaStore.MediaColumns._ID
-+                    },
-+                    MediaStore.MediaColumns.DATA + "='" + audiblePath + "'",
-+                    null, null);
-+            if (c != null && c.getCount() > 0) {
-+                c.moveToFirst();
-+                long id = c.getLong(0);
-+                c.close();
-+                uri = Uri.withAppendedPath(
-+                        Uri.parse(MEDIA_CONTENT_URI), "" + id);
-+            }
-+            if (uri != null)
-+                RingtoneManager.setActualDefaultRingtoneUri(context, type, uri);
-+        } else {
-+            return false;
-+        }
-+        return true;
-+    }
-+
-+}
--- 
-2.11.1
-
diff --git a/patches/packages/apps/masquerade/0002-Finalize-masquerade-rootless-functionality-with-Subs.patch b/patches/packages/apps/masquerade/0002-Finalize-masquerade-rootless-functionality-with-Subs.patch
deleted file mode 100644 (file)
index 0388c7d..0000000
+++ /dev/null
@@ -1,952 +0,0 @@
-From 30c65ea40cde9403e3a5bf7030b50b75a57061d5 Mon Sep 17 00:00:00 2001
-From: Ivan Iskandar <iiiiskandar14@gmail.com>
-Date: Mon, 6 Feb 2017 22:20:49 +0700
-Subject: [PATCH 2/3] Finalize masquerade rootless functionality with
- Substratum [2/3]
-
-Change-Id: I69d3bfd6740dbbf8e864962aff764dd7707d1329
----
- .../masquerade/substratum/services/JobService.java | 605 ++++++++++++++++-----
- .../java/masquerade/substratum/utils/IOUtils.java  |  45 +-
- .../masquerade/substratum/utils/SoundUtils.java    |   2 +-
- 3 files changed, 503 insertions(+), 149 deletions(-)
-
-diff --git a/app/src/main/java/masquerade/substratum/services/JobService.java b/app/src/main/java/masquerade/substratum/services/JobService.java
-index 3c1b859..20cf166 100644
---- a/app/src/main/java/masquerade/substratum/services/JobService.java
-+++ b/app/src/main/java/masquerade/substratum/services/JobService.java
-@@ -1,4 +1,3 @@
--
- package masquerade.substratum.services;
- import android.app.ActivityManager;
-@@ -15,6 +14,7 @@ import android.content.IntentFilter;
- import android.content.IntentSender;
- import android.content.om.IOverlayManager;
- import android.content.om.OverlayInfo;
-+import android.content.pm.IPackageDeleteObserver;
- import android.content.pm.IPackageInstallObserver2;
- import android.content.pm.IPackageManager;
- import android.content.pm.PackageInstaller;
-@@ -26,6 +26,7 @@ import android.graphics.Typeface;
- import android.media.RingtoneManager;
- import android.os.Binder;
- import android.os.Bundle;
-+import android.os.Environment;
- import android.os.FileUtils;
- import android.os.Handler;
- import android.os.HandlerThread;
-@@ -81,12 +82,18 @@ public class JobService extends Service {
-     public static final String JOB_TIME_KEY = "job_time_key";
-     public static final String INSTALL_LIST_KEY = "install_list";
-     public static final String UNINSTALL_LIST_KEY = "uninstall_list";
--    public static final String WITH_RESTART_UI_KEY = "with_restart_ui";
-     public static final String BOOTANIMATION_FILE_NAME = "bootanimation_file_name";
-     public static final String FONTS_PID = "fonts_pid";
-     public static final String FONTS_FILENAME = "fonts_filename";
-     public static final String AUDIO_PID = "audio_pid";
-     public static final String AUDIO_FILENAME = "audio_filename";
-+    public static final String ENABLE_LIST_KEY = "enable_list";
-+    public static final String DISABLE_LIST_KEY = "disable_list";
-+    public static final String PRIORITY_LIST_KEY = "priority_list";
-+    public static final String SOURCE_FILE_KEY = "source_file";
-+    public static final String DESTINATION_FILE_KEY = "destination_file";
-+    public static final String WITH_DELETE_PARENT_KEY = "delete_parent";
-+    public static final String PROFILE_NAME_KEY = "profile_name";
-     public static final String COMMAND_VALUE_JOB_COMPLETE = "job_complete";
-     public static final String COMMAND_VALUE_INSTALL = "install";
-     public static final String COMMAND_VALUE_UNINSTALL = "uninstall";
-@@ -95,6 +102,13 @@ public class JobService extends Service {
-     public static final String COMMAND_VALUE_BOOTANIMATION = "bootanimation";
-     public static final String COMMAND_VALUE_FONTS = "fonts";
-     public static final String COMMAND_VALUE_AUDIO = "audio";
-+    public static final String COMMAND_VALUE_ENABLE = "enable";
-+    public static final String COMMAND_VALUE_DISABLE = "disable";
-+    public static final String COMMAND_VALUE_PRIORITY = "priority";
-+    public static final String COMMAND_VALUE_COPY = "copy";
-+    public static final String COMMAND_VALUE_MOVE = "move";
-+    public static final String COMMAND_VALUE_DELETE = "delete";
-+    public static final String COMMAND_VALUE_PROFILE = "profile";
-     private static IOverlayManager mOMS;
-     private static IPackageManager mPM;
-@@ -104,6 +118,7 @@ public class JobService extends Service {
-     private MainHandler mMainHandler;
-     private final List<Runnable> mJobQueue = new ArrayList<>(0);
-     private long mLastJobTime;
-+    private boolean mIsRunning;
-     @Override
-     public void onCreate() {
-@@ -121,11 +136,10 @@ public class JobService extends Service {
-             return START_NOT_STICKY;
-         }
--        // one job at a time please
--        // if (isProcessing()) {
--        // log("Got start command while still processing last job, aborting");
--        // return START_NOT_STICKY;
--        // }
-+        // Don't run job if there is another running job
-+        mIsRunning = false;
-+        if (isProcessing()) mIsRunning = true;
-+
-         // filter out duplicate intents
-         long jobTime = intent.getLongExtra(JOB_TIME_KEY, 1);
-         if (jobTime == 1 || jobTime == mLastJobTime) {
-@@ -156,9 +170,7 @@ public class JobService extends Service {
-             for (String _package : packages) {
-                 jobs_to_add.add(new Remover(_package));
-             }
--            if (intent.getBooleanExtra(WITH_RESTART_UI_KEY, false)) {
--                jobs_to_add.add(new UiResetJob());
--            }
-+            if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-         } else if (TextUtils.equals(command, COMMAND_VALUE_RESTART_UI)) {
-             jobs_to_add.add(new UiResetJob());
-         } else if (TextUtils.equals(command, COMMAND_VALUE_CONFIGURATION_SHIM)) {
-@@ -180,6 +192,44 @@ public class JobService extends Service {
-             String fileName = intent.getStringExtra(AUDIO_FILENAME);
-             jobs_to_add.add(new SoundsJob(pid, fileName));
-             jobs_to_add.add(new UiResetJob());
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_ENABLE)) {
-+            List<String> packages = intent.getStringArrayListExtra(ENABLE_LIST_KEY);
-+            for (String _package : packages) {
-+                jobs_to_add.add(new Enabler(_package));
-+            }
-+            if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_DISABLE)) {
-+            List<String> packages = intent.getStringArrayListExtra(DISABLE_LIST_KEY);
-+            for (String _package : packages) {
-+                jobs_to_add.add(new Disabler(_package));
-+            }
-+            if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_PRIORITY)) {
-+            List<String> packages = intent.getStringArrayListExtra(PRIORITY_LIST_KEY);
-+            jobs_to_add.add(new PriorityJob(packages));
-+            if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_COPY)) {
-+            String source = intent.getStringExtra(SOURCE_FILE_KEY);
-+            String destination = intent.getStringExtra(DESTINATION_FILE_KEY);
-+            jobs_to_add.add(new CopyJob(source, destination));
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_MOVE)) {
-+            String source = intent.getStringExtra(SOURCE_FILE_KEY);
-+            String destination = intent.getStringExtra(DESTINATION_FILE_KEY);
-+            jobs_to_add.add(new MoveJob(source, destination));
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_DELETE)) {
-+            String dir = intent.getStringExtra(SOURCE_FILE_KEY);
-+            if (intent.getBooleanExtra(WITH_DELETE_PARENT_KEY, true)) {
-+                jobs_to_add.add(new DeleteJob(dir));
-+            } else {
-+                for (File child : new File(dir).listFiles()) {
-+                    jobs_to_add.add(new DeleteJob(child.getAbsolutePath()));
-+                }
-+            }
-+        } else if (TextUtils.equals(command, COMMAND_VALUE_PROFILE)) {
-+            List<String> enable = intent.getStringArrayListExtra(ENABLE_LIST_KEY);
-+            List<String> disable = intent.getStringArrayListExtra(DISABLE_LIST_KEY);
-+            String profile = intent.getStringExtra(PROFILE_NAME_KEY);
-+            jobs_to_add.add(new ProfileJob(profile, disable, enable));
-         }
-         if (jobs_to_add.size() > 0) {
-@@ -233,7 +283,8 @@ public class JobService extends Service {
-     private void install(String path, IPackageInstallObserver2 observer) {
-         try {
--            getPM().installPackageAsUser(path, observer, PackageManager.INSTALL_REPLACE_EXISTING,
-+            getPM().installPackageAsUser(path, observer,
-+                    PackageManager.INSTALL_REPLACE_EXISTING,
-                     null,
-                     UserHandle.USER_SYSTEM);
-         } catch (Exception e) {
-@@ -241,22 +292,17 @@ public class JobService extends Service {
-         }
-     }
--    private void uninstall(String packageName) {
-+    private void uninstall(String packageName, IPackageDeleteObserver observer) {
-         try {
--            final LocalIntentReceiver receiver = new LocalIntentReceiver();
--            getPM().getPackageInstaller().uninstall(packageName, null /* callerPackageName */, 0,
--                    receiver.getIntentSender(), UserHandle.USER_SYSTEM);
--            final Intent result = receiver.getResult();
--            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
--                    PackageInstaller.STATUS_FAILURE);
-+            getPM().deletePackageAsUser(packageName, observer, 0, UserHandle.USER_SYSTEM);
-         } catch (Exception e) {
-             e.printStackTrace();
-         }
-     }
--    private void disableOverlay(String packageName) {
-+    private void switchOverlay(String packageName, boolean enable) {
-         try {
--            getOMS().setEnabled(packageName, false, UserHandle.USER_SYSTEM, false);
-+            getOMS().setEnabled(packageName, enable, UserHandle.USER_SYSTEM, false);
-         } catch (RemoteException e) {
-             e.printStackTrace();
-         }
-@@ -265,14 +311,25 @@ public class JobService extends Service {
-     private boolean isOverlayEnabled(String packageName) {
-         boolean enabled = false;
-         try {
--            OverlayInfo info = getOMS().getOverlayInfo(packageName, UserHandle.USER_ALL);
--            enabled = info.isEnabled();
-+            OverlayInfo info = getOMS().getOverlayInfo(packageName, UserHandle.USER_SYSTEM);
-+            if (info != null) {
-+                enabled = info.isEnabled();
-+            } else {
-+                log("info is null");
-+            }
-         } catch (RemoteException e) {
-             e.printStackTrace();
-         }
-         return enabled;
-     }
-+    private boolean shouldRestartUi(List<String> overlays) {
-+        for (String o : overlays) {
-+            if (o.startsWith("com.android.systemui")) return true;
-+        }
-+        return false;
-+    }
-+
-     private void copyFonts(String pid, String zipFileName) {
-         // prepare local cache dir for font package assembly
-         log("Copy Fonts - Package ID = " + pid + " filename = " + zipFileName);
-@@ -328,23 +385,26 @@ public class JobService extends Service {
-         IOUtils.createFontDirIfNotExists();
-         IOUtils.copyFolder(cacheDir.getAbsolutePath(), IOUtils.SYSTEM_THEME_FONT_PATH);
--        // set permissions on font files and config xml
--        File themeFonts = new File(IOUtils.SYSTEM_THEME_FONT_PATH);
--        for (File f : themeFonts.listFiles()) {
--            FileUtils.setPermissions(f,
--                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
--        }
--
-         // let system know it's time for a font change
--        SystemProperties.set("sys.refresh_theme", "1");
--        float fontSize = Float.valueOf(Settings.System.getString(
--                getContentResolver(), Settings.System.FONT_SCALE));
--        Settings.System.putString(getContentResolver(),
--                Settings.System.FONT_SCALE, String.valueOf(fontSize + 0.0000001));
-+        refreshFonts();
-     }
-     private void clearFonts() {
-         IOUtils.deleteThemedFonts();
-+        refreshFonts();
-+    }
-+
-+    private void refreshFonts() {
-+        // set permissions on font files and config xml
-+        File themeFonts = new File(IOUtils.SYSTEM_THEME_FONT_PATH);
-+        if (themeFonts.exists()) {
-+            // Set permissions
-+            IOUtils.setPermissionsRecursive(themeFonts,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH);
-+        }
-+
-+        // let system know it's time for a font change
-         SystemProperties.set("sys.refresh_theme", "1");
-         Typeface.recreateDefaults();
-         float fontSize = Float.valueOf(Settings.System.getString(
-@@ -395,56 +455,29 @@ public class JobService extends Service {
-             File effect_tick_ogg = new File(getCacheDir(), "/SoundsCache/ui/Effect_Tick.ogg");
-             if (effect_tick_ogg.exists()) {
-                 IOUtils.bufferedCopy(effect_tick_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.ogg"));
--                SoundUtils.setUIAudible(this, effect_tick_ogg, new File
--                        ("/data/system/theme/audio/ui/Effect_Tick.ogg"), RingtoneManager
--                        .TYPE_RINGTONE, "Effect_Tick");
-             } else if (effect_tick_mp3.exists()) {
-                 IOUtils.bufferedCopy(effect_tick_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.mp3"));
--                SoundUtils.setUIAudible(this, effect_tick_mp3, new File
--                        ("/data/system/theme/audio/ui/Effect_Tick.mp3"), RingtoneManager
--                        .TYPE_RINGTONE, "Effect_Tick");
--            } else {
--                SoundUtils.setDefaultUISounds(getContentResolver(), "lock_sound", "Lock.ogg");
-             }
-             File new_lock_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Lock.mp3");
-             File new_lock_ogg = new File(getCacheDir(), "/SoundsCache/ui/Lock.ogg");
-             if (new_lock_ogg.exists()) {
-                 IOUtils.bufferedCopy(new_lock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Lock.ogg"));
--                SoundUtils.setUISounds(getContentResolver(), "lock_sound", "/data/system/theme/audio/ui/Lock.ogg");
-             } else if (new_lock_mp3.exists()) {
-                 IOUtils.bufferedCopy(new_lock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Lock.mp3"));
--                SoundUtils.setUISounds(getContentResolver(), "lock_sound", "/data/system/theme/audio/ui/Lock.mp3");
--            } else {
--                SoundUtils.setDefaultUISounds(getContentResolver(), "lock_sound", "Lock.ogg");
-             }
-             File new_unlock_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Unlock.mp3");
-             File new_unlock_ogg = new File(getCacheDir(), "/SoundsCache/ui/Unlock.ogg");
-             if (new_unlock_ogg.exists()) {
-                 IOUtils.bufferedCopy(new_unlock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Unlock.ogg"));
--                SoundUtils.setUISounds(getContentResolver(), "unlock_sound", "/data/system/theme/audio/ui/Unlock.ogg");
-             } else if (new_unlock_mp3.exists()) {
-                 IOUtils.bufferedCopy(new_unlock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Unlock.mp3"));
--                SoundUtils.setUISounds(getContentResolver(), "unlock_sound", "/data/system/theme/audio/ui/Unlock.mp3");
--            } else {
--                SoundUtils.setDefaultUISounds(getContentResolver(), "unlock_sound", "Unlock.ogg");
-             }
-             File new_lowbattery_mp3 = new File(getCacheDir(), "/SoundsCache/ui/LowBattery.mp3");
-             File new_lowbattery_ogg = new File(getCacheDir(), "/SoundsCache/ui/LowBattery.ogg");
-             if (new_lowbattery_ogg.exists()) {
-                 IOUtils.bufferedCopy(new_lowbattery_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.ogg"));
--                SoundUtils.setUISounds(getContentResolver(), "low_battery_sound", "/data/system/theme/audio/ui/LowBattery.ogg");
-             } else if (new_lowbattery_mp3.exists()) {
-                 IOUtils.bufferedCopy(new_lowbattery_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.mp3"));
--                SoundUtils.setUISounds(getContentResolver(), "low_battery_sound", "/data/system/theme/audio/ui/LowBattery.mp3");
--            } else {
--                SoundUtils.setDefaultUISounds(getContentResolver(), "low_battery_sound", "LowBattery.ogg");
--            }
--            File uiSounds = new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH);
--            if (uiSounds.exists() && uiSounds.isDirectory()) {
--                for (File f : uiSounds.listFiles()) {
--                    FileUtils.setPermissions(f,
--                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
--                }
-             }
-         }
-         File alarmCache = new File(getCacheDir(), "/SoundsCache/alarms/");
-@@ -454,27 +487,8 @@ public class JobService extends Service {
-             File new_alarm_ogg = new File(getCacheDir(), "/SoundsCache/alarms/alarm.ogg");
-             if (new_alarm_ogg.exists()) {
-                 IOUtils.bufferedCopy(new_alarm_ogg, new File(IOUtils.SYSTEM_THEME_ALARM_PATH + File.separator + "alarm.ogg"));
--                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_alarm_metadata", "string", SUBSTRATUM_PACKAGE);
--                SoundUtils.setAudible(this, new File("/data/system/theme/audio/alarms/alarm.ogg"),
--                        new File(alarmCache.getAbsolutePath(), "alarm.ogg"),
--                        RingtoneManager.TYPE_ALARM,
--                        getSubsContext().getString(metaDataId));
-             } else if (new_alarm_mp3.exists()) {
-                 IOUtils.bufferedCopy(new_alarm_mp3, new File(IOUtils.SYSTEM_THEME_ALARM_PATH + File.separator + "alarm.mp3"));
--                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_alarm_metadata", "string", SUBSTRATUM_PACKAGE);
--                SoundUtils.setAudible(this, new File("/data/system/theme/audio/alarms/alarm.mp3"),
--                        new File(alarmCache.getAbsolutePath(), "alarm.mp3"),
--                        RingtoneManager.TYPE_ALARM,
--                        getSubsContext().getString(metaDataId));
--            } else {
--                SoundUtils.setDefaultAudible(this, RingtoneManager.TYPE_ALARM);
--            }
--            File alarms = new File(IOUtils.SYSTEM_THEME_ALARM_PATH);
--            if (alarms.exists() && alarms.isDirectory()) {
--                for (File f : alarms.listFiles()) {
--                    FileUtils.setPermissions(f,
--                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
--                }
-             }
-         }
-         File notifCache = new File(getCacheDir(), "/SoundsCache/notifications/");
-@@ -484,27 +498,8 @@ public class JobService extends Service {
-             File new_notif_ogg = new File(getCacheDir(), "/SoundsCache/notifications/notification.ogg");
-             if (new_notif_ogg.exists()) {
-                 IOUtils.bufferedCopy(new_notif_ogg, new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.ogg"));
--                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_notification_metadata", "string", SUBSTRATUM_PACKAGE);
--                SoundUtils.setAudible(this, new File("/data/system/theme/audio/notifications/notification.ogg"),
--                        new File(notifCache.getAbsolutePath(), "notification.ogg"),
--                        RingtoneManager.TYPE_NOTIFICATION,
--                        getSubsContext().getString(metaDataId));
-             } else if (new_notif_mp3.exists()) {
-                 IOUtils.bufferedCopy(new_notif_mp3, new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.mp3"));
--                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_notification_metadata", "string", SUBSTRATUM_PACKAGE);
--                SoundUtils.setAudible(this, new File("/data/system/theme/audio/notifications/notification.mp3"),
--                        new File(notifCache.getAbsolutePath(), "notification.mp3"),
--                        RingtoneManager.TYPE_NOTIFICATION,
--                        getSubsContext().getString(metaDataId));
--            } else {
--                SoundUtils.setDefaultAudible(this, RingtoneManager.TYPE_NOTIFICATION);
--            }
--            File notifs = new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH);
--            if (notifs.exists() && notifs.isDirectory()) {
--                for (File f : notifs.listFiles()) {
--                    FileUtils.setPermissions(f,
--                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
--                }
-             }
-         }
-         File ringtoneCache = new File(getCacheDir(), "/SoundsCache/ringtones/");
-@@ -514,29 +509,13 @@ public class JobService extends Service {
-             File new_ring_ogg = new File(getCacheDir(), "/SoundsCache/ringtones/ringtone.ogg");
-             if (new_ring_ogg.exists()) {
-                 IOUtils.bufferedCopy(new_ring_ogg, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH + File.separator + "ringtone.ogg"));
--                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_ringtone_metadata", "string", SUBSTRATUM_PACKAGE);
--                SoundUtils.setAudible(this, new File("/data/system/theme/audio/ringtones/ringtone.ogg"),
--                        new File(notifCache.getAbsolutePath(), "ringtone.ogg"),
--                        RingtoneManager.TYPE_RINGTONE,
--                        getSubsContext().getString(metaDataId));
-             } else if (new_ring_mp3.exists()) {
-                 IOUtils.bufferedCopy(new_ring_mp3, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH + File.separator + "ringtone.mp3"));
--                int metaDataId = getSubsContext().getResources().getIdentifier("content_resolver_ringtone_metadata", "string", SUBSTRATUM_PACKAGE);
--                SoundUtils.setAudible(this, new File("/data/system/theme/audio/ringtones/ringtone.mp3"),
--                        new File(notifCache.getAbsolutePath(), "ringtone.mp3"),
--                        RingtoneManager.TYPE_RINGTONE,
--                        getSubsContext().getString(metaDataId));
--            } else {
--                SoundUtils.setDefaultAudible(this, RingtoneManager.TYPE_RINGTONE);
--            }
--            File rings = new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH);
--            if (rings.exists() && rings.isDirectory()) {
--                for (File f : rings.listFiles()) {
--                    FileUtils.setPermissions(f,
--                            FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO, -1, -1);
--                }
-             }
-         }
-+
-+        // let system know it's time for a sound change
-+        refreshSounds();
-     }
-     private void clearSounds(Context ctx) {
-@@ -550,6 +529,121 @@ public class JobService extends Service {
-                 "LowBattery.ogg");
-     }
-+    private void refreshSounds () {
-+        File soundsDir = new File(IOUtils.SYSTEM_THEME_AUDIO_PATH);
-+        if (soundsDir.exists()) {
-+            // Set permissions
-+            IOUtils.setPermissionsRecursive(soundsDir,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IRWXO,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH);
-+
-+            File uiDir = new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH);
-+            if (uiDir.exists()) {
-+                File effect_tick_mp3 = new File(uiDir, "Effect_Tick.mp3");
-+                File effect_tick_ogg = new File(uiDir, "Effect_Tick.ogg");
-+                if (effect_tick_mp3.exists()) {
-+                    SoundUtils.setUIAudible(this, effect_tick_mp3,
-+                            effect_tick_mp3, RingtoneManager.TYPE_RINGTONE,
-+                            "Effect_Tick");
-+                } else if (effect_tick_ogg.exists()) {
-+                    SoundUtils.setUIAudible(this, effect_tick_ogg,
-+                            effect_tick_ogg, RingtoneManager.TYPE_RINGTONE,
-+                            "Effect_Tick");
-+                } else {
-+                    SoundUtils.setDefaultUISounds(getContentResolver(),
-+                            "Effect_Tick",
-+                            "Effect_Tick.ogg");
-+                }
-+
-+                File lock_mp3 = new File(uiDir, "Lock.mp3");
-+                File lock_ogg = new File(uiDir, "Lock.ogg");
-+                if (lock_mp3.exists()) {
-+                    SoundUtils.setUISounds(getContentResolver(), "lock_sound",
-+                            lock_mp3.getAbsolutePath());
-+                } else if (lock_ogg.exists()) {
-+                    SoundUtils.setUISounds(getContentResolver(), "lock_sound",
-+                            lock_ogg.getAbsolutePath());
-+                } else {
-+                    SoundUtils.setDefaultUISounds(getContentResolver(),
-+                            "lock_sound", "Lock.ogg");
-+                }
-+
-+                File unlock_mp3 = new File(uiDir, "Unlock.mp3");
-+                File unlock_ogg = new File(uiDir, "Unlock.ogg");
-+                if (unlock_mp3.exists()) {
-+                    SoundUtils.setUISounds(getContentResolver(), "unlock_sound",
-+                            unlock_mp3.getAbsolutePath());
-+                } else if (unlock_ogg.exists()) {
-+                    SoundUtils.setUISounds(getContentResolver(), "unlock_sound",
-+                            unlock_ogg.getAbsolutePath());
-+                } else {
-+                    SoundUtils.setDefaultUISounds(getContentResolver(),
-+                            "unlock_sound", "Unlock.ogg");
-+                }
-+
-+                File lowbattery_mp3 = new File(uiDir, "LowBattery.mp3");
-+                File lowbattery_ogg = new File(uiDir, "LowBattery.ogg");
-+                if (lowbattery_mp3.exists()) {
-+                    SoundUtils.setUISounds(getContentResolver(), "low_battery_sound",
-+                            lowbattery_mp3.getAbsolutePath());
-+                } else if (lowbattery_ogg.exists()) {
-+                    SoundUtils.setUISounds(getContentResolver(), "low_battery_sound",
-+                            lowbattery_ogg.getAbsolutePath());
-+                } else {
-+                    SoundUtils.setDefaultUISounds(getContentResolver(),
-+                            "low_battery_sound", "LowBattery.ogg");
-+                }
-+            }
-+
-+            File notifDir = new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH);
-+            if (notifDir.exists()) {
-+                int metaDataId = getSubsContext().getResources().getIdentifier(
-+                        "content_resolver_notification_metadata",
-+                        "string", SUBSTRATUM_PACKAGE);
-+
-+                File notification_mp3 = new File(notifDir, "notification.mp3");
-+                File notification_ogg = new File(notifDir, "notification.ogg");
-+                if (notification_mp3.exists()) {
-+                    SoundUtils.setAudible(this, notification_mp3,
-+                            notification_mp3,
-+                            RingtoneManager.TYPE_NOTIFICATION,
-+                            getSubsContext().getString(metaDataId));
-+                } else if (notification_ogg.exists()) {
-+                    SoundUtils.setAudible(this, notification_ogg,
-+                            notification_ogg,
-+                            RingtoneManager.TYPE_NOTIFICATION,
-+                            getSubsContext().getString(metaDataId));
-+                } else {
-+                    SoundUtils.setDefaultAudible(this,
-+                            RingtoneManager.TYPE_NOTIFICATION);
-+                }
-+            }
-+
-+            File ringtoneDir = new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH);
-+            if (ringtoneDir.exists()) {
-+                int metaDataId = getSubsContext().getResources().getIdentifier(
-+                        "content_resolver_notification_metadata",
-+                        "string", SUBSTRATUM_PACKAGE);
-+
-+                File ringtone_mp3 = new File(ringtoneDir, "ringtone.mp3");
-+                File ringtone_ogg = new File(ringtoneDir, "ringtone.ogg");
-+                if (ringtone_mp3.exists()) {
-+                    SoundUtils.setAudible(this, ringtone_mp3,
-+                            ringtone_mp3,
-+                            RingtoneManager.TYPE_RINGTONE,
-+                            getSubsContext().getString(metaDataId));
-+                } else if (ringtone_ogg.exists()) {
-+                    SoundUtils.setAudible(this, ringtone_ogg,
-+                            ringtone_ogg,
-+                            RingtoneManager.TYPE_RINGTONE,
-+                            getSubsContext().getString(metaDataId));
-+                } else {
-+                    SoundUtils.setDefaultAudible(this,
-+                            RingtoneManager.TYPE_RINGTONE);
-+                }
-+            }
-+        }
-+    }
-     private void copyBootAnimation(String fileName) {
-         try {
-             clearBootAnimation();
-@@ -557,8 +651,8 @@ public class JobService extends Service {
-             File dest = new File(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH);
-             IOUtils.bufferedCopy(source, dest);
-             source.delete();
--            FileUtils.setPermissions(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH,
--                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
-+            IOUtils.setPermissions(dest,
-+                    FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IROTH);
-         } catch (Exception e) {
-             e.printStackTrace();
-         }
-@@ -689,7 +783,7 @@ public class JobService extends Service {
-                     synchronized (mJobQueue) {
-                         job = mJobQueue.get(0);
-                     }
--                    if (job != null) {
-+                    if (job != null && !mIsRunning) {
-                         job.run();
-                     }
-                     break;
-@@ -698,8 +792,10 @@ public class JobService extends Service {
-                     synchronized (mJobQueue) {
-                         mJobQueue.remove(toRemove);
-                         if (mJobQueue.size() > 0) {
-+                            mIsRunning = false;
-                             this.sendEmptyMessage(MESSAGE_CHECK_QUEUE);
-                         } else {
-+                            mIsRunning = false;
-                             log("Job queue empty! All done");
-                             mMainHandler.sendEmptyMessage(MainHandler.MSG_JOB_QUEUE_EMPTY);
-                         }
-@@ -835,7 +931,7 @@ public class JobService extends Service {
-         }
-     }
--    private class Installer implements Runnable, IPackageInstallObserver2 {
-+    private class Installer implements Runnable {
-         String mPath;
-         public Installer(String path) {
-@@ -843,27 +939,28 @@ public class JobService extends Service {
-         }
-         @Override
--        public IBinder asBinder() {
--            return null;
-+        public void run() {
-+            log("Installer - installing " + mPath);
-+            PackageInstallObserver observer = new PackageInstallObserver(Installer.this);
-+            install(mPath, observer);
-         }
-+    }
--        @Override
--        public void onUserActionRequired(Intent intent) throws RemoteException {
--            log("Installer - user action required callback with " + mPath);
-+    private class PackageInstallObserver extends IPackageInstallObserver2.Stub {
-+        Object mObject;
-+
-+        public PackageInstallObserver(Object _object) {
-+            mObject = _object;
-         }
--        @Override
--        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
--                Bundle extras) throws RemoteException {
--            log("Installer - successfully installed " + basePackageName + " from " + mPath);
--            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE, Installer.this);
--            mJobHandler.sendMessage(message);
-+        public void onUserActionRequired(Intent intent) throws RemoteException {
-+            log("Installer - user action required callback");
-         }
--        @Override
--        public void run() {
--            log("Installer - installing " + mPath);
--            install(mPath, this);
-+        public void onPackageInstalled(String packageName, int returnCode, String msg, Bundle extras) {
-+            log("Installer - successfully installed " + packageName);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE, mObject);
-+            mJobHandler.sendMessage(message);
-         }
-     }
-@@ -876,12 +973,242 @@ public class JobService extends Service {
-         @Override
-         public void run() {
-+
-+            // TODO: Fix isOverlayEnabled function, for now it's causing NPE
-             if (isOverlayEnabled(mPackage)) {
-                 log("Remover - disabling overlay for " + mPackage);
--                disableOverlay(mPackage);
-+                switchOverlay(mPackage, false);
-             }
-+
-             log("Remover - uninstalling " + mPackage);
--            uninstall(mPackage);
-+            PackageDeleteObserver observer = new PackageDeleteObserver(Remover.this);
-+            uninstall(mPackage, observer);
-+        }
-+    }
-+
-+    private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
-+        Object mObject;
-+
-+        public PackageDeleteObserver(Object _object) {
-+            mObject = _object;
-+        }
-+
-+        public void packageDeleted(String packageName, int returnCode) {
-+            log("Remover - successfully removed " + packageName);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE, mObject);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class Enabler implements Runnable {
-+        String mPackage;
-+
-+        public Enabler(String _package) {
-+            mPackage = _package;
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("Enabler - enabling overlay for " + mPackage);
-+            switchOverlay(mPackage, true);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    Enabler.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class Disabler implements Runnable {
-+        String mPackage;
-+
-+        public Disabler(String _package) {
-+            mPackage = _package;
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("Disabler - disabling overlay for " + mPackage);
-+            switchOverlay(mPackage, false);
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    Disabler.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class PriorityJob implements Runnable {
-+        List<String> mPackages;
-+
-+        public PriorityJob(List<String> _packages) {
-+            mPackages = _packages;
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("PriorityJob - processing priority changes");
-+            try {
-+                int size = mPackages.size();
-+                for (int i = 0; i < size-1; i++) {
-+                    String parentName = mPackages.get(i);
-+                    String packageName = mPackages.get(i+1);
-+                    getOMS().setPriority(packageName, parentName, UserHandle.USER_SYSTEM);
-+                }
-+            } catch (RemoteException e) {
-+                e.printStackTrace();
-+            }
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    PriorityJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class CopyJob implements Runnable {
-+        String mSource;
-+        String mDestination;
-+
-+        public CopyJob(String _source, String _destination) {
-+            mSource = _source;
-+            mDestination = _destination;
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("CopyJob - copying " + mSource + " to " + mDestination);
-+            File sourceFile = new File(mSource);
-+            if (sourceFile.exists()) {
-+                if (sourceFile.isFile()) {
-+                    IOUtils.bufferedCopy(mSource, mDestination);
-+                } else {
-+                    IOUtils.copyFolder(mSource, mDestination);
-+                }
-+            } else {
-+                log("CopyJob - " + mSource + " is not exist! aborting...");
-+            }
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    CopyJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class MoveJob implements Runnable {
-+        String mSource;
-+        String mDestination;
-+
-+        public MoveJob(String _source, String _destination) {
-+            mSource = _source;
-+            mDestination = _destination;
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("MoveJob - moving " + mSource + " to " + mDestination);
-+            File sourceFile = new File(mSource);
-+            if (sourceFile.exists()) {
-+                if (sourceFile.isFile()) {
-+                    IOUtils.bufferedCopy(mSource, mDestination);
-+                } else {
-+                    IOUtils.copyFolder(mSource, mDestination);
-+                }
-+                IOUtils.deleteRecursive(sourceFile);
-+            } else {
-+                log("MoveJob - " + mSource + " is not exist! aborting...");
-+            }
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    MoveJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class DeleteJob implements Runnable {
-+        String mFileOrDirectory;
-+
-+        public DeleteJob(String _directory) {
-+            mFileOrDirectory = _directory;
-+        }
-+
-+        @Override
-+        public void run() {
-+            log("DeleteJob - deleting " + mFileOrDirectory);
-+            File file = new File(mFileOrDirectory);
-+            if (file.exists()) {
-+                IOUtils.deleteRecursive(file);
-+            } else {
-+                log("DeleteJob - " + mFileOrDirectory + " is already deleted!");
-+            }
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    DeleteJob.this);
-+            mJobHandler.sendMessage(message);
-+        }
-+    }
-+
-+    private class ProfileJob implements Runnable {
-+        String mProfileName;
-+        List<String> mToBeDisabled;
-+        List<String> mToBeEnabled;
-+
-+        public ProfileJob(String _name, List<String> _toBeDisabled, List<String> _toBeEnabled) {
-+            mProfileName = _name;
-+            mToBeDisabled = _toBeDisabled;
-+            mToBeEnabled = _toBeEnabled;
-+        }
-+
-+        @Override
-+        public void run() {
-+            boolean restartUi = false;
-+            log("Applying profile...");
-+
-+            // Need to restart SystemUI?
-+            restartUi = shouldRestartUi(mToBeEnabled) || shouldRestartUi(mToBeDisabled);
-+
-+            // Clear system theme folder content
-+            File themeDir = new File(IOUtils.SYSTEM_THEME_PATH);
-+            for (File f : themeDir.listFiles()) {
-+                IOUtils.deleteRecursive(f);
-+            }
-+
-+            // Process theme folder
-+            File profileDir = new File(Environment.getExternalStorageDirectory()
-+                    .getAbsolutePath() + "/substratum/profiles/" +
-+                    mProfileName + "/theme");
-+
-+            if (profileDir.exists()) {
-+                File profileFonts = new File(profileDir, "fonts");
-+                if (profileFonts.exists()) {
-+                    IOUtils.copyFolder(profileFonts, new File(IOUtils.SYSTEM_THEME_FONT_PATH));
-+                    refreshFonts();
-+                    restartUi = true;
-+                } else {
-+                    clearFonts();
-+                }
-+
-+                File profileSounds = new File(profileDir, "audio");
-+                if (profileSounds.exists()) {
-+                    IOUtils.copyFolder(profileSounds, new File(IOUtils.SYSTEM_THEME_AUDIO_PATH));
-+                    refreshSounds();
-+                    restartUi = true;
-+                } else {
-+                    clearSounds(JobService.this);
-+                }
-+            }
-+
-+            // Disable all overlays installed
-+            for (String overlay : mToBeDisabled) {
-+                switchOverlay(overlay, false);
-+            }
-+
-+            // Enable provided overlays
-+            for (String overlay : mToBeEnabled) {
-+                switchOverlay(overlay, true);
-+            }
-+
-+            // Restart SystemUI when needed
-+            if (restartUi) {
-+                synchronized(mJobQueue) {
-+                    mJobQueue.add(new UiResetJob());
-+                }
-+            }
-+
-+            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-+                    ProfileJob.this);
-+            mJobHandler.sendMessage(message);
-         }
-     }
-diff --git a/app/src/main/java/masquerade/substratum/utils/IOUtils.java b/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-index 092c58c..06b5260 100644
---- a/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-+++ b/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-@@ -40,8 +40,8 @@ public class IOUtils {
-         if (!dirExists(dirPath)) {
-             File dir = new File(dirPath);
-             if (dir.mkdir()) {
--                FileUtils.setPermissions(dir, FileUtils.S_IRWXU |
--                        FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH, -1, -1);
-+                setPermissions(dir, FileUtils.S_IRWXU | FileUtils.S_IRWXG |
-+                        FileUtils.S_IROTH | FileUtils.S_IXOTH);
-             }
-         }
-     }
-@@ -77,7 +77,7 @@ public class IOUtils {
-             e.printStackTrace();
-         }
-     }
--    
-+
-     public static void deleteThemedAudio() {
-         try {
-             deleteRecursive(new File(SYSTEM_THEME_UI_SOUNDS_PATH));
-@@ -89,20 +89,28 @@ public class IOUtils {
-         }
-     }
--    public static void copyFolder(String source, String dest) {
--        File dir = new File(source);
--        File[] files = dir.listFiles();
-+    public static void copyFolder(File source, File dest) {
-+        if (!dest.exists()) dest.mkdirs();
-+        File[] files = source.listFiles();
-         for (File file : files) {
-             try {
--                String sourceFile = dir + File.separator + file.getName();
--                String destinationFile = dest + File.separator + file.getName();
--                bufferedCopy(new File(sourceFile), new File(destinationFile));
-+                File newFile = new File(dest.getAbsolutePath() + File.separator +
-+                        file.getName());
-+                if (file.isFile()) {
-+                    bufferedCopy(file, newFile);
-+                } else {
-+                    copyFolder(file, newFile);
-+                }
-             } catch (Exception e) {
-                 e.printStackTrace();
-             }
-         }
-     }
-+    public static void copyFolder(String source, String dest) {
-+        copyFolder(new File(source), new File(dest));
-+    }
-+
-     public static void unzip(String source, String destination) {
-         try (ZipInputStream inputStream = new ZipInputStream(
-                 new BufferedInputStream(new FileInputStream(source)))) {
-@@ -167,4 +175,23 @@ public class IOUtils {
-         fileOrDirectory.delete();
-     }
-+    public static void setPermissions(File path, int permissions) {
-+        FileUtils.setPermissions(path, permissions, -1, -1);
-+    }
-+
-+    public static void setPermissionsRecursive(File dir, int file, int folder) {
-+        if (dir.isDirectory()) {
-+            for (File child : dir.listFiles()) {
-+                if (child.isDirectory()) {
-+                    setPermissionsRecursive(child, file, folder);
-+                    setPermissions(child, folder);
-+                } else {
-+                    setPermissions(child, file);
-+                }
-+            }
-+            setPermissions(dir, folder);
-+        } else {
-+            setPermissions(dir, file);
-+        }
-+    }
- }
-diff --git a/app/src/main/java/masquerade/substratum/utils/SoundUtils.java b/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-index 72c6052..dda38eb 100644
---- a/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-+++ b/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-@@ -27,7 +27,7 @@ public class SoundUtils {
-     private static final String MEDIA_CONTENT_URI = "content://media/internal/audio/media";
-     public static void updateGlobalSettings(ContentResolver resolver, String uri, String val) {
--        Settings.Global.putStringForUser(resolver, uri, val, UserHandle.USER_ALL);
-+        Settings.Global.putStringForUser(resolver, uri, val, UserHandle.USER_SYSTEM);
-     }
-     public static boolean setUISounds(ContentResolver resolver, String sound_name, String location) {
--- 
-2.11.1
-
diff --git a/patches/packages/apps/masquerade/0003-Release-23-Introduce-the-rootless-solution-for-Masqu.patch b/patches/packages/apps/masquerade/0003-Release-23-Introduce-the-rootless-solution-for-Masqu.patch
deleted file mode 100644 (file)
index 7bdff15..0000000
+++ /dev/null
@@ -1,2644 +0,0 @@
-From 63b419e89e730b3186fce7cb8a4b95e5b56f81fe Mon Sep 17 00:00:00 2001
-From: Nicholas Chum <nicholaschum@gmail.com>
-Date: Tue, 14 Feb 2017 00:56:09 -0500
-Subject: [PATCH 3/3] Release 23: Introduce the rootless solution for
- Masquerade [3/3]
-
-Huge thanks to @bigrushdog, @iskandar1023 and @Surge1223 for all
-the hard work put into this.
-
-Clean-up commit by @nicholaschum
-- Introduce Java8 integration
-- Remove all the receivers
-- Remove all the unused imports, methods and permissions.
-- Reformat and optimize all Java files, drawables and XML files.
-- Make sure the project is Android Studio ready
-- Ensure that all permissions are declared Protected if in AS.
-
-To build this in Android Studio (without platform key), you must copy
-the "android.jar" built from your AOSP+OMS build environment to
-%AndroidSDK%/platforms/android-25/android.jar (back up your original
-copy). Then all you have to do is import masquerade as a gradle
-project to Android Studio and you are set!
-
-Change-Id: Ie350497ac5cfaf39c062235b90e3832f8072c7a8
----
- app/build.gradle                                   |  32 +-
- app/src/main/AndroidManifest.xml                   |  49 ++-
- .../substratum/receivers/BootReceiver.java         |  13 -
- .../substratum/receivers/UninstallReceiver.java    |  47 ---
- .../masquerade/substratum/services/JobService.java | 462 +++++++++------------
- .../masquerade/substratum/services/MasqDemo.java   | 137 ------
- .../java/masquerade/substratum/utils/IOUtils.java  |  37 +-
- .../masquerade/substratum/utils/SoundUtils.java    |  72 ++--
- app/src/main/res/mipmap-hdpi/ic_launcher.png       | Bin 0 -> 2240 bytes
- .../main/res/mipmap-hdpi/substratum_masquerade.png | Bin 2246 -> 0 bytes
- app/src/main/res/mipmap-mdpi/ic_launcher.png       | Bin 0 -> 1848 bytes
- .../main/res/mipmap-mdpi/substratum_masquerade.png | Bin 2094 -> 0 bytes
- app/src/main/res/mipmap-xhdpi/ic_launcher.png      | Bin 0 -> 2733 bytes
- .../res/mipmap-xhdpi/substratum_masquerade.png     | Bin 2734 -> 0 bytes
- app/src/main/res/mipmap-xxhdpi/ic_launcher.png     | Bin 0 -> 3874 bytes
- .../res/mipmap-xxhdpi/substratum_masquerade.png    | Bin 3894 -> 0 bytes
- app/src/main/res/mipmap-xxxhdpi/ic_launcher.png    | Bin 0 -> 4947 bytes
- .../res/mipmap-xxxhdpi/substratum_masquerade.png   | Bin 4966 -> 0 bytes
- app/src/main/res/values/styles.xml                 |   1 -
- gradlew                                            |   0
- gradlew.bat                                        | 180 ++++----
- 21 files changed, 408 insertions(+), 622 deletions(-)
- delete mode 100644 app/src/main/java/masquerade/substratum/receivers/BootReceiver.java
- delete mode 100644 app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java
- delete mode 100644 app/src/main/java/masquerade/substratum/services/MasqDemo.java
- create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png
- delete mode 100755 app/src/main/res/mipmap-hdpi/substratum_masquerade.png
- create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png
- delete mode 100755 app/src/main/res/mipmap-mdpi/substratum_masquerade.png
- create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png
- delete mode 100755 app/src/main/res/mipmap-xhdpi/substratum_masquerade.png
- create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png
- delete mode 100755 app/src/main/res/mipmap-xxhdpi/substratum_masquerade.png
- create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
- delete mode 100755 app/src/main/res/mipmap-xxxhdpi/substratum_masquerade.png
- mode change 100755 => 100644 gradlew
-
-diff --git a/app/build.gradle b/app/build.gradle
-index 265096a..a2694a8 100644
---- a/app/build.gradle
-+++ b/app/build.gradle
-@@ -1,7 +1,7 @@
- apply plugin: 'com.android.application'
- android {
--    compileSdkVersion 23
-+    compileSdkVersion 25
-     buildToolsVersion "23.0.3"
-     lintOptions {
-@@ -12,25 +12,41 @@ android {
-     applicationVariants.all { variant ->
-         variant.outputs.each { output ->
-             output.outputFile = new File(
--                    output.outputFile.parent, "masquerade_beta_testers" + versionCode + ".apk")
-+                    output.outputFile.parent, "masquerade_" + versionCode + ".apk")
-         }
-     }
-     defaultConfig {
-         applicationId "masquerade.substratum"
--        minSdkVersion 21
--        targetSdkVersion 23
--        versionCode 20
--        versionName "twenty - procyon"
-+        minSdkVersion 25
-+        targetSdkVersion 25
-+        versionCode 23
-+        versionName "twenty three"
-+    }
-+
-+    defaultConfig {
-+        jackOptions {
-+            enabled true
-+        }
-+    }
-+
-+    compileOptions {
-+        incremental true
-+        sourceCompatibility JavaVersion.VERSION_1_8
-+        targetCompatibility JavaVersion.VERSION_1_8
-+    }
-+
-+    dexOptions {
-+        javaMaxHeapSize '2048m'
-     }
-     buildTypes {
-         debug {
--            minifyEnabled true
-+            minifyEnabled false
-             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-         }
-         release {
--            minifyEnabled true
-+            minifyEnabled false
-             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-         }
-     }
-diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
-index 13db0f9..2554839 100644
---- a/app/src/main/AndroidManifest.xml
-+++ b/app/src/main/AndroidManifest.xml
-@@ -1,40 +1,39 @@
-+<!--suppress AndroidUnknownAttribute -->
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
--          package="masquerade.substratum"
--          android:versionCode="21"
--          android:versionName="twentyone - something"
-+          xmlns:tools="http://schemas.android.com/tools"
-           coreApp="true"
--          android:sharedUserId="android.uid.system">
-+          package="masquerade.substratum"
-+          android:sharedUserId="android.uid.system"
-+          android:versionCode="23"
-+          android:versionName="twenty three"
-+          tools:ignore="GradleOverrides">
-     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
--    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
-     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
--    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
--    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
--    <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
--    <uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
-+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
-+    <uses-permission
-+        android:name="android.permission.FORCE_STOP_PACKAGES"
-+        tools:ignore="ProtectedPermissions"/>
-+    <uses-permission
-+        android:name="android.permission.DELETE_PACKAGES"
-+        tools:ignore="ProtectedPermissions"/>
-+    <uses-permission
-+        android:name="android.permission.INSTALL_PACKAGES"
-+        tools:ignore="ProtectedPermissions"/>
-     <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"/>
-     <uses-permission android:name="android.permission.MODIFY_OVERLAYS"/>
-     <application
--        android:allowBackup="true"
--        android:icon="@mipmap/substratum_masquerade"
-+        android:allowBackup="false"
-+        android:icon="@mipmap/ic_launcher"
-         android:label="@string/app_name"
-         android:supportsRtl="true"
--        android:theme="@style/AppTheme">
--        <receiver android:name=".receivers.BootReceiver">
--            <intent-filter>
--                <action android:name="android.intent.action.BOOT_COMPLETED"/>
--            </intent-filter>
--        </receiver>
--        <receiver android:name=".receivers.UninstallReceiver">
--            <intent-filter>
--                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
--                <data android:scheme="package"/>
--            </intent-filter>
--        </receiver>
--        <service android:name=".services.JobService"
-+        android:theme="@style/AppTheme"
-+        tools:ignore="GoogleAppIndexingWarning">
-+        <service
-+            android:name=".services.JobService"
-             android:exported="true"
--            android:permission="android.permission.MODIFY_OVERLAYS" />
-+            android:permission="android.permission.MODIFY_OVERLAYS"/>
-     </application>
- </manifest>
-diff --git a/app/src/main/java/masquerade/substratum/receivers/BootReceiver.java b/app/src/main/java/masquerade/substratum/receivers/BootReceiver.java
-deleted file mode 100644
-index ebc0c8b..0000000
---- a/app/src/main/java/masquerade/substratum/receivers/BootReceiver.java
-+++ /dev/null
-@@ -1,13 +0,0 @@
--package masquerade.substratum.receivers;
--
--import android.content.BroadcastReceiver;
--import android.content.Context;
--import android.content.Intent;
--
--
--public class BootReceiver extends BroadcastReceiver {
--    @Override
--    public void onReceive(Context context, Intent intent) {
--        // do something
--    }
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java b/app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java
-deleted file mode 100644
-index b377e27..0000000
---- a/app/src/main/java/masquerade/substratum/receivers/UninstallReceiver.java
-+++ /dev/null
-@@ -1,47 +0,0 @@
--package masquerade.substratum.receivers;
--
--import android.content.BroadcastReceiver;
--import android.content.Context;
--import android.content.Intent;
--import android.net.Uri;
--import android.os.AsyncTask;
--import android.os.Environment;
--import android.util.Log;
--
--import java.util.ArrayList;
--import java.util.List;
--
--
--public class UninstallReceiver extends BroadcastReceiver {
--    @Override
--    public void onReceive(Context context, Intent intent) {
--        if ("android.intent.action.PACKAGE_REMOVED".equals(intent.getAction())) {
--            Uri packageName = intent.getData();
--            if (packageName.toString().substring(8).equals("projekt.substratum")) {
--//                new performUninstalls().execute("");
--            }
--        }
--    }
--/*
--    public class performUninstalls extends AsyncTask<String, Integer, String> {
--        @Override
--        protected String doInBackground(String... sUrl) {
--            // Substratum was uninstalled, uninstall all remaining overlays
--            Log.d("Masquerade",
--                    "Substratum was uninstalled, so all remaining overlays will be removed...");
--            String[] state4 = {Environment.getExternalStorageDirectory()
--                    .getAbsolutePath() + "/.substratum/current_overlays.xml", "4"};
--            String[] state5 = {Environment.getExternalStorageDirectory()
--                    .getAbsolutePath() + "/.substratum/current_overlays.xml", "5"};
--            List<String> state5overlays = ReadOverlaysFile.main(state5);
--            ArrayList<String> all_overlays = new ArrayList<>(ReadOverlaysFile.main(state4));
--            all_overlays.addAll(state5overlays);
--            for (int i = 0; i < all_overlays.size(); i++) {
--                Log.d("Masquerade", "Uninstalling overlay: " + all_overlays.get(i));
--                Root.runCommand("pm uninstall " + all_overlays.get(i));
--            }
--            return null;
--        }
--    }
--    */
--}
-\ No newline at end of file
-diff --git a/app/src/main/java/masquerade/substratum/services/JobService.java b/app/src/main/java/masquerade/substratum/services/JobService.java
-index 20cf166..0ecd279 100644
---- a/app/src/main/java/masquerade/substratum/services/JobService.java
-+++ b/app/src/main/java/masquerade/substratum/services/JobService.java
-@@ -1,3 +1,23 @@
-+/*
-+ * Copyright (c) 2017 Project Substratum
-+ *
-+ * 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 2
-+ * 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, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-+ * Also add information on how to contact you by electronic and paper mail.
-+ *
-+ */
-+
- package masquerade.substratum.services;
- import android.app.ActivityManager;
-@@ -7,24 +27,19 @@ import android.app.Service;
- import android.content.BroadcastReceiver;
- import android.content.ComponentName;
- import android.content.Context;
--import android.content.IIntentReceiver;
--import android.content.IIntentSender;
- import android.content.Intent;
- import android.content.IntentFilter;
--import android.content.IntentSender;
- import android.content.om.IOverlayManager;
- import android.content.om.OverlayInfo;
- import android.content.pm.IPackageDeleteObserver;
- import android.content.pm.IPackageInstallObserver2;
- import android.content.pm.IPackageManager;
--import android.content.pm.PackageInstaller;
- import android.content.pm.PackageManager;
- import android.content.pm.PackageManager.NameNotFoundException;
- import android.content.res.AssetManager;
- import android.content.res.Configuration;
- import android.graphics.Typeface;
- import android.media.RingtoneManager;
--import android.os.Binder;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.FileUtils;
-@@ -42,42 +57,21 @@ import android.provider.Settings;
- import android.text.TextUtils;
- import android.util.Log;
--import java.io.BufferedInputStream;
--import java.io.BufferedOutputStream;
- import java.io.File;
--import java.io.FileInputStream;
--import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
--import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Locale;
--import java.util.concurrent.SynchronousQueue;
--import java.util.concurrent.TimeUnit;
--import java.util.zip.ZipEntry;
--import java.util.zip.ZipInputStream;
-+import java.util.stream.Collectors;
- import masquerade.substratum.utils.IOUtils;
- import masquerade.substratum.utils.SoundUtils;
--import com.android.internal.statusbar.IStatusBarService;
--
- public class JobService extends Service {
--    private static final String TAG = JobService.class.getSimpleName();
--    private static final boolean DEBUG = true;
--
--    private static final String MASQUERADE_TOKEN = "masquerade_token";
--    private static final String SUBSTRATUM_PACKAGE = "projekt.substratum";
--    private static final String[] AUTHORIZED_CALLERS = new String[] {
--            SUBSTRATUM_PACKAGE,
--            "masquerade.substratum"
--    };
--
-     public static final String INTENT_STATUS_CHANGED = "masquerade.substratum.STATUS_CHANGED";
--
-     public static final String PRIMARY_COMMAND_KEY = "primary_command_key";
-     public static final String JOB_TIME_KEY = "job_time_key";
-     public static final String INSTALL_LIST_KEY = "install_list";
-@@ -109,20 +103,47 @@ public class JobService extends Service {
-     public static final String COMMAND_VALUE_MOVE = "move";
-     public static final String COMMAND_VALUE_DELETE = "delete";
-     public static final String COMMAND_VALUE_PROFILE = "profile";
--
-+    private static final String TAG = JobService.class.getSimpleName();
-+    private static final boolean DEBUG = true;
-+    private static final String MASQUERADE_TOKEN = "masquerade_token";
-+    private static final String MASQUERADE_PACKAGE = "masquerade.substratum";
-+    private static final String SUBSTRATUM_PACKAGE = "projekt.substratum";
-+    private static final String[] AUTHORIZED_CALLERS = new String[]{
-+            MASQUERADE_PACKAGE,
-+            SUBSTRATUM_PACKAGE,
-+    };
-     private static IOverlayManager mOMS;
-     private static IPackageManager mPM;
--
--    private HandlerThread mWorker;
-+    private final List<Runnable> mJobQueue = new ArrayList<>(0);
-     private JobHandler mJobHandler;
-     private MainHandler mMainHandler;
--    private final List<Runnable> mJobQueue = new ArrayList<>(0);
-     private long mLastJobTime;
-     private boolean mIsRunning;
-+    private static IOverlayManager getOMS() {
-+        if (mOMS == null) {
-+            mOMS = IOverlayManager.Stub.asInterface(
-+                    ServiceManager.getService("overlay"));
-+        }
-+        return mOMS;
-+    }
-+
-+    private static IPackageManager getPM() {
-+        if (mPM == null) {
-+            mPM = IPackageManager.Stub.asInterface(
-+                    ServiceManager.getService("package"));
-+        }
-+        return mPM;
-+    }
-+
-+    public static void log(String msg) {
-+        if (DEBUG) Log.e(TAG, msg);
-+    }
-+
-     @Override
-     public void onCreate() {
--        mWorker = new HandlerThread("BackgroundWorker", Process.THREAD_PRIORITY_BACKGROUND);
-+        HandlerThread mWorker = new HandlerThread("BackgroundWorker", Process
-+                .THREAD_PRIORITY_BACKGROUND);
-         mWorker.start();
-         mJobHandler = new JobHandler(mWorker.getLooper());
-         mMainHandler = new MainHandler(Looper.getMainLooper());
-@@ -137,39 +158,33 @@ public class JobService extends Service {
-         }
-         // Don't run job if there is another running job
--        mIsRunning = false;
--        if (isProcessing()) mIsRunning = true;
-+        mIsRunning = isProcessing();
--        // filter out duplicate intents
-+        // Filter out duplicate intents
-         long jobTime = intent.getLongExtra(JOB_TIME_KEY, 1);
-         if (jobTime == 1 || jobTime == mLastJobTime) {
--            log("got empty jobtime or duplicate job time, aborting");
-+            log("Received empty job time or duplicate job time, aborting");
-             return START_NOT_STICKY;
-         }
-         mLastJobTime = jobTime;
--        // must have a primary command
-+        // Must have a primary command
-         String command = intent.getStringExtra(PRIMARY_COMMAND_KEY);
-         if (TextUtils.isEmpty(command)) {
--            log("Got empty primary command, aborting");
-+            log("Received empty primary command, aborting");
-             return START_NOT_STICKY;
-         }
--        // queue up the job
--
-+        // Queue up the job
-         List<Runnable> jobs_to_add = new ArrayList<>(0);
--        log("Starting job with primary command " + command + " With job time " + jobTime);
-+        log("Starting job with primary command \'" + command + "\', with job time: " + jobTime);
-         if (TextUtils.equals(command, COMMAND_VALUE_INSTALL)) {
-             List<String> paths = intent.getStringArrayListExtra(INSTALL_LIST_KEY);
--            for (String path : paths) {
--                jobs_to_add.add(new Installer(path));
--            }
-+            jobs_to_add.addAll(paths.stream().map(Installer::new).collect(Collectors.toList()));
-         } else if (TextUtils.equals(command, COMMAND_VALUE_UNINSTALL)) {
-             List<String> packages = intent.getStringArrayListExtra(UNINSTALL_LIST_KEY);
--            for (String _package : packages) {
--                jobs_to_add.add(new Remover(_package));
--            }
-+            jobs_to_add.addAll(packages.stream().map(Remover::new).collect(Collectors.toList()));
-             if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-         } else if (TextUtils.equals(command, COMMAND_VALUE_RESTART_UI)) {
-             jobs_to_add.add(new UiResetJob());
-@@ -194,15 +209,11 @@ public class JobService extends Service {
-             jobs_to_add.add(new UiResetJob());
-         } else if (TextUtils.equals(command, COMMAND_VALUE_ENABLE)) {
-             List<String> packages = intent.getStringArrayListExtra(ENABLE_LIST_KEY);
--            for (String _package : packages) {
--                jobs_to_add.add(new Enabler(_package));
--            }
-+            jobs_to_add.addAll(packages.stream().map(Enabler::new).collect(Collectors.toList()));
-             if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-         } else if (TextUtils.equals(command, COMMAND_VALUE_DISABLE)) {
-             List<String> packages = intent.getStringArrayListExtra(DISABLE_LIST_KEY);
--            for (String _package : packages) {
--                jobs_to_add.add(new Disabler(_package));
--            }
-+            jobs_to_add.addAll(packages.stream().map(Disabler::new).collect(Collectors.toList()));
-             if (shouldRestartUi(packages)) jobs_to_add.add(new UiResetJob());
-         } else if (TextUtils.equals(command, COMMAND_VALUE_PRIORITY)) {
-             List<String> packages = intent.getStringArrayListExtra(PRIORITY_LIST_KEY);
-@@ -241,7 +252,6 @@ public class JobService extends Service {
-                 mJobHandler.sendEmptyMessage(JobHandler.MESSAGE_CHECK_QUEUE);
-             }
-         }
--
-         return START_NOT_STICKY;
-     }
-@@ -252,35 +262,13 @@ public class JobService extends Service {
-     @Override
-     public void onDestroy() {
--
-     }
-     private boolean isProcessing() {
-         return mJobQueue.size() > 0;
-     }
--    private class LocalService extends Binder {
--        public JobService getService() {
--            return JobService.this;
--        }
--    }
--
--    private static IOverlayManager getOMS() {
--        if (mOMS == null) {
--            mOMS = IOverlayManager.Stub.asInterface(
--                    ServiceManager.getService("overlay"));
--        }
--        return mOMS;
--    }
--
--    private static IPackageManager getPM() {
--        if (mPM == null) {
--            mPM = IPackageManager.Stub.asInterface(
--                    ServiceManager.getService("package"));
--        }
--        return mPM;
--    }
--
-+    @SuppressWarnings("deprecation")
-     private void install(String path, IPackageInstallObserver2 observer) {
-         try {
-             getPM().installPackageAsUser(path, observer,
-@@ -292,6 +280,7 @@ public class JobService extends Service {
-         }
-     }
-+    @SuppressWarnings("deprecation")
-     private void uninstall(String packageName, IPackageDeleteObserver observer) {
-         try {
-             getPM().deletePackageAsUser(packageName, observer, 0, UserHandle.USER_SYSTEM);
-@@ -315,7 +304,7 @@ public class JobService extends Service {
-             if (info != null) {
-                 enabled = info.isEnabled();
-             } else {
--                log("info is null");
-+                log("OverlayInfo is null.");
-             }
-         } catch (RemoteException e) {
-             e.printStackTrace();
-@@ -331,24 +320,25 @@ public class JobService extends Service {
-     }
-     private void copyFonts(String pid, String zipFileName) {
--        // prepare local cache dir for font package assembly
-+        // Prepare local cache dir for font package assembly
-         log("Copy Fonts - Package ID = " + pid + " filename = " + zipFileName);
-         File cacheDir = new File(getCacheDir(), "/FontCache/");
-         if (cacheDir.exists()) {
-             IOUtils.deleteRecursive(cacheDir);
-         }
--        cacheDir.mkdir();
-+        boolean created = cacheDir.mkdir();
-+        if (!created) log("Could not create cache directory...");
--        // copy system fonts into our cache dir
-+        // Copy system fonts into our cache dir
-         IOUtils.copyFolder("/system/fonts", cacheDir.getAbsolutePath());
--        // append zip to filename since it is probably removed
-+        // Append zip to filename since it is probably removed
-         // for list presentation
-         if (!zipFileName.endsWith(".zip")) {
-             zipFileName = zipFileName + ".zip";
-         }
--        // copy target themed fonts zip to our cache dir
-+        // Copy target themed fonts zip to our cache dir
-         Context themeContext = getAppContext(pid);
-         AssetManager am = themeContext.getAssets();
-         try {
-@@ -360,12 +350,13 @@ public class JobService extends Service {
-             e.printStackTrace();
-         }
--        // unzip new fonts and delete zip file, overwriting any system fonts
-+        // Unzip new fonts and delete zip file, overwriting any system fonts
-         File fontZip = new File(getCacheDir(), "/FontCache/" + zipFileName);
-         IOUtils.unzip(fontZip.getAbsolutePath(), cacheDir.getAbsolutePath());
--        fontZip.delete();
-+        boolean deleted = fontZip.delete();
-+        if (!deleted) log("Could not delete ZIP file...");
--        // check if theme zip included a fonts.xml. If not, Substratum
-+        // Check if theme zip included a fonts.xml. If not, Substratum
-         // is kind enough to provide one for us in it's assets
-         try {
-             File testConfig = new File(getCacheDir(), "/FontCache/" + "fonts.xml");
-@@ -380,12 +371,12 @@ public class JobService extends Service {
-             e.printStackTrace();
-         }
--        // prepare system theme fonts folder and copy new fonts folder from our cache
-+        // Prepare system theme fonts folder and copy new fonts folder from our cache
-         IOUtils.deleteThemedFonts();
-         IOUtils.createFontDirIfNotExists();
-         IOUtils.copyFolder(cacheDir.getAbsolutePath(), IOUtils.SYSTEM_THEME_FONT_PATH);
--        // let system know it's time for a font change
-+        // Let system know it's time for a font change
-         refreshFonts();
-     }
-@@ -395,7 +386,7 @@ public class JobService extends Service {
-     }
-     private void refreshFonts() {
--        // set permissions on font files and config xml
-+        // Set permissions on font files and config xml
-         File themeFonts = new File(IOUtils.SYSTEM_THEME_FONT_PATH);
-         if (themeFonts.exists()) {
-             // Set permissions
-@@ -404,7 +395,7 @@ public class JobService extends Service {
-                     FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH);
-         }
--        // let system know it's time for a font change
-+        // Let system know it's time for a font change
-         SystemProperties.set("sys.refresh_theme", "1");
-         Typeface.recreateDefaults();
-         float fontSize = Float.valueOf(Settings.System.getString(
-@@ -414,21 +405,23 @@ public class JobService extends Service {
-     }
-     private void applyThemedSounds(String pid, String zipFileName) {
--        // prepare local cache dir for font package assembly
--        log("Copy sounds - Package ID = " + pid + " filename = " + zipFileName);
-+        // Prepare local cache dir for font package assembly
-+        log("CopySounds - Package ID = \'" + pid + "\'");
-+        log("CopySounds - File name = \'" + zipFileName + "\'");
-         File cacheDir = new File(getCacheDir(), "/SoundsCache/");
-         if (cacheDir.exists()) {
-             IOUtils.deleteRecursive(cacheDir);
-         }
--        cacheDir.mkdir();
-+        boolean created = cacheDir.mkdir();
-+        if (!created) log("Could not create cache directory...");
--        // append zip to filename since it is probably removed
-+        // Append zip to filename since it is probably removed
-         // for list presentation
-         if (!zipFileName.endsWith(".zip")) {
-             zipFileName = zipFileName + ".zip";
-         }
--        // copy target themed sounds zip to our cache dir
-+        // Copy target themed sounds zip to our cache dir
-         Context themeContext = getAppContext(pid);
-         AssetManager am = themeContext.getAssets();
-         try {
-@@ -440,10 +433,11 @@ public class JobService extends Service {
-             e.printStackTrace();
-         }
--        // unzip new sounds and delete zip file
-+        // Unzip new sounds and delete zip file
-         File soundsZip = new File(getCacheDir(), "/SoundsCache/" + zipFileName);
-         IOUtils.unzip(soundsZip.getAbsolutePath(), cacheDir.getAbsolutePath());
--        soundsZip.delete();
-+        boolean deleted = soundsZip.delete();
-+        if (!deleted) log("Could not delete ZIP file...");
-         clearSounds(this);
-         IOUtils.createAudioDirIfNotExists();
-@@ -454,30 +448,38 @@ public class JobService extends Service {
-             File effect_tick_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Effect_Tick.mp3");
-             File effect_tick_ogg = new File(getCacheDir(), "/SoundsCache/ui/Effect_Tick.ogg");
-             if (effect_tick_ogg.exists()) {
--                IOUtils.bufferedCopy(effect_tick_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.ogg"));
-+                IOUtils.bufferedCopy(effect_tick_ogg, new File(IOUtils
-+                        .SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.ogg"));
-             } else if (effect_tick_mp3.exists()) {
--                IOUtils.bufferedCopy(effect_tick_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.mp3"));
-+                IOUtils.bufferedCopy(effect_tick_mp3, new File(IOUtils
-+                        .SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Effect_Tick.mp3"));
-             }
-             File new_lock_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Lock.mp3");
-             File new_lock_ogg = new File(getCacheDir(), "/SoundsCache/ui/Lock.ogg");
-             if (new_lock_ogg.exists()) {
--                IOUtils.bufferedCopy(new_lock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Lock.ogg"));
-+                IOUtils.bufferedCopy(new_lock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH +
-+                        File.separator + "Lock.ogg"));
-             } else if (new_lock_mp3.exists()) {
--                IOUtils.bufferedCopy(new_lock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Lock.mp3"));
-+                IOUtils.bufferedCopy(new_lock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH +
-+                        File.separator + "Lock.mp3"));
-             }
-             File new_unlock_mp3 = new File(getCacheDir(), "/SoundsCache/ui/Unlock.mp3");
-             File new_unlock_ogg = new File(getCacheDir(), "/SoundsCache/ui/Unlock.ogg");
-             if (new_unlock_ogg.exists()) {
--                IOUtils.bufferedCopy(new_unlock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Unlock.ogg"));
-+                IOUtils.bufferedCopy(new_unlock_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH
-+                        + File.separator + "Unlock.ogg"));
-             } else if (new_unlock_mp3.exists()) {
--                IOUtils.bufferedCopy(new_unlock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "Unlock.mp3"));
-+                IOUtils.bufferedCopy(new_unlock_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH
-+                        + File.separator + "Unlock.mp3"));
-             }
-             File new_lowbattery_mp3 = new File(getCacheDir(), "/SoundsCache/ui/LowBattery.mp3");
-             File new_lowbattery_ogg = new File(getCacheDir(), "/SoundsCache/ui/LowBattery.ogg");
-             if (new_lowbattery_ogg.exists()) {
--                IOUtils.bufferedCopy(new_lowbattery_ogg, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.ogg"));
-+                IOUtils.bufferedCopy(new_lowbattery_ogg, new File(IOUtils
-+                        .SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.ogg"));
-             } else if (new_lowbattery_mp3.exists()) {
--                IOUtils.bufferedCopy(new_lowbattery_mp3, new File(IOUtils.SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.mp3"));
-+                IOUtils.bufferedCopy(new_lowbattery_mp3, new File(IOUtils
-+                        .SYSTEM_THEME_UI_SOUNDS_PATH + File.separator + "LowBattery.mp3"));
-             }
-         }
-         File alarmCache = new File(getCacheDir(), "/SoundsCache/alarms/");
-@@ -486,20 +488,26 @@ public class JobService extends Service {
-             File new_alarm_mp3 = new File(getCacheDir(), "/SoundsCache/alarms/alarm.mp3");
-             File new_alarm_ogg = new File(getCacheDir(), "/SoundsCache/alarms/alarm.ogg");
-             if (new_alarm_ogg.exists()) {
--                IOUtils.bufferedCopy(new_alarm_ogg, new File(IOUtils.SYSTEM_THEME_ALARM_PATH + File.separator + "alarm.ogg"));
-+                IOUtils.bufferedCopy(new_alarm_ogg, new File(IOUtils.SYSTEM_THEME_ALARM_PATH +
-+                        File.separator + "alarm.ogg"));
-             } else if (new_alarm_mp3.exists()) {
--                IOUtils.bufferedCopy(new_alarm_mp3, new File(IOUtils.SYSTEM_THEME_ALARM_PATH + File.separator + "alarm.mp3"));
-+                IOUtils.bufferedCopy(new_alarm_mp3, new File(IOUtils.SYSTEM_THEME_ALARM_PATH +
-+                        File.separator + "alarm.mp3"));
-             }
-         }
-         File notifCache = new File(getCacheDir(), "/SoundsCache/notifications/");
-         if (notifCache.exists() && notifCache.isDirectory()) {
-             IOUtils.createNotificationDirIfNotExists();
--            File new_notif_mp3 = new File(getCacheDir(), "/SoundsCache/notifications/notification.mp3");
--            File new_notif_ogg = new File(getCacheDir(), "/SoundsCache/notifications/notification.ogg");
-+            File new_notif_mp3 = new File(getCacheDir(), "/SoundsCache/notifications/notification" +
-+                    ".mp3");
-+            File new_notif_ogg = new File(getCacheDir(), "/SoundsCache/notifications/notification" +
-+                    ".ogg");
-             if (new_notif_ogg.exists()) {
--                IOUtils.bufferedCopy(new_notif_ogg, new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.ogg"));
-+                IOUtils.bufferedCopy(new_notif_ogg, new File(IOUtils
-+                        .SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.ogg"));
-             } else if (new_notif_mp3.exists()) {
--                IOUtils.bufferedCopy(new_notif_mp3, new File(IOUtils.SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.mp3"));
-+                IOUtils.bufferedCopy(new_notif_mp3, new File(IOUtils
-+                        .SYSTEM_THEME_NOTIFICATION_PATH + File.separator + "notification.mp3"));
-             }
-         }
-         File ringtoneCache = new File(getCacheDir(), "/SoundsCache/ringtones/");
-@@ -508,28 +516,30 @@ public class JobService extends Service {
-             File new_ring_mp3 = new File(getCacheDir(), "/SoundsCache/ringtones/ringtone.mp3");
-             File new_ring_ogg = new File(getCacheDir(), "/SoundsCache/ringtones/ringtone.ogg");
-             if (new_ring_ogg.exists()) {
--                IOUtils.bufferedCopy(new_ring_ogg, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH + File.separator + "ringtone.ogg"));
-+                IOUtils.bufferedCopy(new_ring_ogg, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH +
-+                        File.separator + "ringtone.ogg"));
-             } else if (new_ring_mp3.exists()) {
--                IOUtils.bufferedCopy(new_ring_mp3, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH + File.separator + "ringtone.mp3"));
-+                IOUtils.bufferedCopy(new_ring_mp3, new File(IOUtils.SYSTEM_THEME_RINGTONE_PATH +
-+                        File.separator + "ringtone.mp3"));
-             }
-         }
--        // let system know it's time for a sound change
-+        // Let system know it's time for a sound change
-         refreshSounds();
-     }
-     private void clearSounds(Context ctx) {
-         IOUtils.deleteThemedAudio();
--        SoundUtils.setDefaultAudible(JobService.this, RingtoneManager.TYPE_ALARM);
--        SoundUtils.setDefaultAudible(JobService.this, RingtoneManager.TYPE_NOTIFICATION);
--        SoundUtils.setDefaultAudible(JobService.this, RingtoneManager.TYPE_RINGTONE);
-+        SoundUtils.setDefaultAudible(ctx, RingtoneManager.TYPE_ALARM);
-+        SoundUtils.setDefaultAudible(ctx, RingtoneManager.TYPE_NOTIFICATION);
-+        SoundUtils.setDefaultAudible(ctx, RingtoneManager.TYPE_RINGTONE);
-         SoundUtils.setDefaultUISounds(getContentResolver(), "lock_sound", "Lock.ogg");
-         SoundUtils.setDefaultUISounds(getContentResolver(), "unlock_sound", "Unlock.ogg");
-         SoundUtils.setDefaultUISounds(getContentResolver(), "low_battery_sound",
-                 "LowBattery.ogg");
-     }
--    private void refreshSounds () {
-+    private void refreshSounds() {
-         File soundsDir = new File(IOUtils.SYSTEM_THEME_AUDIO_PATH);
-         if (soundsDir.exists()) {
-             // Set permissions
-@@ -644,13 +654,15 @@ public class JobService extends Service {
-             }
-         }
-     }
-+
-     private void copyBootAnimation(String fileName) {
-         try {
-             clearBootAnimation();
-             File source = new File(fileName);
-             File dest = new File(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH);
-             IOUtils.bufferedCopy(source, dest);
--            source.delete();
-+            boolean deleted = source.delete();
-+            if (!deleted) log("Could not delete source file...");
-             IOUtils.setPermissions(dest,
-                     FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IROTH);
-         } catch (Exception e) {
-@@ -662,21 +674,25 @@ public class JobService extends Service {
-         try {
-             File f = new File(IOUtils.SYSTEM_THEME_BOOTANIMATION_PATH);
-             if (f.exists()) {
--                f.delete();
-+                boolean deleted = f.delete();
-+                if (!deleted) log("Could not delete themed boot animation...");
-             }
-         } catch (Exception e) {
-             e.printStackTrace();
-         }
-     }
-+    @SuppressWarnings({"unchecked", "ConfusingArgumentToVarargsMethod"})
-     private void restartUi() {
-         try {
-             ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
-             Class ActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
-             Method getDefault = ActivityManagerNative.getDeclaredMethod("getDefault", null);
-             Object amn = getDefault.invoke(null, null);
--            Method killApplicationProcess = amn.getClass().getDeclaredMethod("killApplicationProcess", String.class, int.class);
--            stopService(new Intent().setComponent(new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")));
-+            Method killApplicationProcess = amn.getClass().getDeclaredMethod
-+                    ("killApplicationProcess", String.class, int.class);
-+            stopService(new Intent().setComponent(new ComponentName("com.android.systemui", "com" +
-+                    ".android.systemui.SystemUIService")));
-             am.killBackgroundProcesses("com.android.systemui");
-             for (ActivityManager.RunningAppProcessInfo app : am.getRunningAppProcesses()) {
-                 if ("com.android.systemui".equals(app.processName)) {
-@@ -689,15 +705,6 @@ public class JobService extends Service {
-         }
-     }
--    private void killPackage(String packageName) {
--        try {
--            ActivityManagerNative.getDefault().forceStopPackage(packageName,
--                    UserHandle.USER_SYSTEM);
--        } catch (RemoteException e) {
--            e.printStackTrace();
--        }
--    }
--
-     private Context getSubsContext() {
-         return getAppContext(SUBSTRATUM_PACKAGE);
-     }
-@@ -713,45 +720,38 @@ public class JobService extends Service {
-         return ctx;
-     }
--    public static void log(String msg) {
--        if (DEBUG) {
--            Log.e(TAG, msg);
--        }
--    }
--
-     private boolean isCallerAuthorized(Intent intent) {
-         PendingIntent token = null;
-         try {
--            token = (PendingIntent) intent.getParcelableExtra(MASQUERADE_TOKEN);
-+            token = intent.getParcelableExtra(MASQUERADE_TOKEN);
-         } catch (Exception e) {
--            log("Attempt to start serivce without a token, unauthorized");
--        }
--        if (token == null) {
--            return false;
-+            log("Attempting to start service without a token - unauthorized!");
-         }
--        // SECOND: we got a token, validate originating package
--        // if not in our whitelist, return null
-+        if (token == null) return false;
-+        // SECOND: We got a token, validate originating package
-+        // if not in our white list, return null
-         String callingPackage = token.getCreatorPackage();
-         boolean isValidPackage = false;
--        for (int i = 0; i < AUTHORIZED_CALLERS.length; i++) {
--            if (TextUtils.equals(callingPackage, AUTHORIZED_CALLERS[i])) {
--                log(callingPackage
--                        + " is an authorized calling package, next validate calling package perms");
-+        for (String AUTHORIZED_CALLER : AUTHORIZED_CALLERS) {
-+            if (TextUtils.equals(callingPackage, AUTHORIZED_CALLER)) {
-+                log("\'" + callingPackage
-+                        + "\' is an authorized calling package, validating calling package " +
-+                        "permissions...");
-                 isValidPackage = true;
-                 break;
-             }
-         }
-         if (!isValidPackage) {
--            log(callingPackage + " is not an authorized calling package");
-+            log("\'" + callingPackage + "\' is not an authorized calling package.");
-             return false;
-         }
-         return true;
-     }
-     private class MainHandler extends Handler {
--        public static final int MSG_JOB_QUEUE_EMPTY = 1;
-+        static final int MSG_JOB_QUEUE_EMPTY = 1;
--        public MainHandler(Looper looper) {
-+        MainHandler(Looper looper) {
-             super(looper);
-         }
-@@ -771,7 +771,7 @@ public class JobService extends Service {
-         private static final int MESSAGE_CHECK_QUEUE = 1;
-         private static final int MESSAGE_DEQUEUE = 2;
--        public JobHandler(Looper looper) {
-+        JobHandler(Looper looper) {
-             super(looper);
-         }
-@@ -783,9 +783,7 @@ public class JobService extends Service {
-                     synchronized (mJobQueue) {
-                         job = mJobQueue.get(0);
-                     }
--                    if (job != null && !mIsRunning) {
--                        job.run();
--                    }
-+                    if (job != null && !mIsRunning) job.run();
-                     break;
-                 case MESSAGE_DEQUEUE:
-                     Runnable toRemove = (Runnable) msg.obj;
-@@ -796,7 +794,7 @@ public class JobService extends Service {
-                             this.sendEmptyMessage(MESSAGE_CHECK_QUEUE);
-                         } else {
-                             mIsRunning = false;
--                            log("Job queue empty! All done");
-+                            log("Job queue is empty. All done!");
-                             mMainHandler.sendEmptyMessage(MainHandler.MSG_JOB_QUEUE_EMPTY);
-                         }
-                     }
-@@ -808,23 +806,6 @@ public class JobService extends Service {
-         }
-     }
--    private class StopPackageJob implements Runnable {
--        String mPackage;
--
--        public void StopPackageJob(String _package) {
--            mPackage = _package;
--        }
--
--        @Override
--        public void run() {
--            killPackage(mPackage);
--            log("Killed package " + mPackage);
--            Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
--                    StopPackageJob.this);
--            mJobHandler.sendMessage(message);
--        }
--    }
--
-     private class UiResetJob implements Runnable {
-         @Override
-         public void run() {
-@@ -841,7 +822,7 @@ public class JobService extends Service {
-         String mPid;
-         String mFileName;
--        public FontsJob(String pid, String fileName) {
-+        FontsJob(String pid, String fileName) {
-             if (pid == null) {
-                 mClear = true;
-             } else {
-@@ -853,10 +834,10 @@ public class JobService extends Service {
-         @Override
-         public void run() {
-             if (mClear) {
--                log("Resetting system font");
-+                log("Restoring system font...");
-                 clearFonts();
-             } else {
--                log("Setting theme font");
-+                log("Configuring theme font...");
-                 copyFonts(mPid, mFileName);
-             }
-             Intent intent = new Intent(INTENT_STATUS_CHANGED);
-@@ -873,7 +854,7 @@ public class JobService extends Service {
-         String mPid;
-         String mFileName;
--        public SoundsJob(String pid, String fileName) {
-+        SoundsJob(String pid, String fileName) {
-             if (pid == null) {
-                 mClear = true;
-             } else {
-@@ -885,10 +866,10 @@ public class JobService extends Service {
-         @Override
-         public void run() {
-             if (mClear) {
--                log("Resetting system sounds");
-+                log("Restoring system sounds...");
-                 clearSounds(JobService.this);
-             } else {
--                log("Setting theme sounds");
-+                log("Configuring theme sounds...");
-                 applyThemedSounds(mPid, mFileName);
-             }
-             Intent intent = new Intent(INTENT_STATUS_CHANGED);
-@@ -901,14 +882,14 @@ public class JobService extends Service {
-     }
-     private class BootAnimationJob implements Runnable {
--        String mFileName;
-         final boolean mClear;
-+        String mFileName;
--        public BootAnimationJob(boolean clear) {
--            mClear = true;
-+        BootAnimationJob(boolean clear) {
-+            mClear = clear;
-         }
--        public BootAnimationJob(String fileName) {
-+        BootAnimationJob(String fileName) {
-             mFileName = fileName;
-             mClear = false;
-         }
-@@ -916,10 +897,10 @@ public class JobService extends Service {
-         @Override
-         public void run() {
-             if (mClear) {
--                log("Resetting system boot animation");
-+                log("Restoring system boot animation...");
-                 clearBootAnimation();
-             } else {
--                log("Setting themed boot animation");
-+                log("Configuring themed boot animation...");
-                 copyBootAnimation(mFileName);
-             }
-             Intent intent = new Intent(INTENT_STATUS_CHANGED);
-@@ -934,13 +915,13 @@ public class JobService extends Service {
-     private class Installer implements Runnable {
-         String mPath;
--        public Installer(String path) {
-+        Installer(String path) {
-             mPath = path;
-         }
-         @Override
-         public void run() {
--            log("Installer - installing " + mPath);
-+            log("Installer - installing \'" + mPath + "\'...");
-             PackageInstallObserver observer = new PackageInstallObserver(Installer.this);
-             install(mPath, observer);
-         }
-@@ -949,7 +930,7 @@ public class JobService extends Service {
-     private class PackageInstallObserver extends IPackageInstallObserver2.Stub {
-         Object mObject;
--        public PackageInstallObserver(Object _object) {
-+        PackageInstallObserver(Object _object) {
-             mObject = _object;
-         }
-@@ -957,8 +938,9 @@ public class JobService extends Service {
-             log("Installer - user action required callback");
-         }
--        public void onPackageInstalled(String packageName, int returnCode, String msg, Bundle extras) {
--            log("Installer - successfully installed " + packageName);
-+        public void onPackageInstalled(String packageName, int returnCode, String msg, Bundle
-+                extras) {
-+            log("Installer - successfully installed \'" + packageName + "\'!");
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE, mObject);
-             mJobHandler.sendMessage(message);
-         }
-@@ -967,20 +949,19 @@ public class JobService extends Service {
-     private class Remover implements Runnable {
-         String mPackage;
--        public Remover(String _package) {
-+        Remover(String _package) {
-             mPackage = _package;
-         }
-         @Override
-         public void run() {
--
-             // TODO: Fix isOverlayEnabled function, for now it's causing NPE
-             if (isOverlayEnabled(mPackage)) {
--                log("Remover - disabling overlay for " + mPackage);
-+                log("Remover - disabling overlay for \'" + mPackage + "\'...");
-                 switchOverlay(mPackage, false);
-             }
--            log("Remover - uninstalling " + mPackage);
-+            log("Remover - uninstalling \'" + mPackage + "\'...");
-             PackageDeleteObserver observer = new PackageDeleteObserver(Remover.this);
-             uninstall(mPackage, observer);
-         }
-@@ -989,12 +970,12 @@ public class JobService extends Service {
-     private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
-         Object mObject;
--        public PackageDeleteObserver(Object _object) {
-+        PackageDeleteObserver(Object _object) {
-             mObject = _object;
-         }
-         public void packageDeleted(String packageName, int returnCode) {
--            log("Remover - successfully removed " + packageName);
-+            log("Remover - successfully removed \'" + packageName + "\'");
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE, mObject);
-             mJobHandler.sendMessage(message);
-         }
-@@ -1003,13 +984,13 @@ public class JobService extends Service {
-     private class Enabler implements Runnable {
-         String mPackage;
--        public Enabler(String _package) {
-+        Enabler(String _package) {
-             mPackage = _package;
-         }
-         @Override
-         public void run() {
--            log("Enabler - enabling overlay for " + mPackage);
-+            log("Enabler - enabling overlay for \'" + mPackage + "\'...");
-             switchOverlay(mPackage, true);
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-                     Enabler.this);
-@@ -1020,13 +1001,13 @@ public class JobService extends Service {
-     private class Disabler implements Runnable {
-         String mPackage;
--        public Disabler(String _package) {
-+        Disabler(String _package) {
-             mPackage = _package;
-         }
-         @Override
-         public void run() {
--            log("Disabler - disabling overlay for " + mPackage);
-+            log("Disabler - disabling overlay for \'" + mPackage + "\'...");
-             switchOverlay(mPackage, false);
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-                     Disabler.this);
-@@ -1037,18 +1018,18 @@ public class JobService extends Service {
-     private class PriorityJob implements Runnable {
-         List<String> mPackages;
--        public PriorityJob(List<String> _packages) {
-+        PriorityJob(List<String> _packages) {
-             mPackages = _packages;
-         }
-         @Override
-         public void run() {
--            log("PriorityJob - processing priority changes");
-+            log("PriorityJob - processing priority changes...");
-             try {
-                 int size = mPackages.size();
--                for (int i = 0; i < size-1; i++) {
-+                for (int i = 0; i < size - 1; i++) {
-                     String parentName = mPackages.get(i);
--                    String packageName = mPackages.get(i+1);
-+                    String packageName = mPackages.get(i + 1);
-                     getOMS().setPriority(packageName, parentName, UserHandle.USER_SYSTEM);
-                 }
-             } catch (RemoteException e) {
-@@ -1064,14 +1045,14 @@ public class JobService extends Service {
-         String mSource;
-         String mDestination;
--        public CopyJob(String _source, String _destination) {
-+        CopyJob(String _source, String _destination) {
-             mSource = _source;
-             mDestination = _destination;
-         }
-         @Override
-         public void run() {
--            log("CopyJob - copying " + mSource + " to " + mDestination);
-+            log("CopyJob - copying \'" + mSource + "\' to \'" + mDestination + "\'...");
-             File sourceFile = new File(mSource);
-             if (sourceFile.exists()) {
-                 if (sourceFile.isFile()) {
-@@ -1080,7 +1061,7 @@ public class JobService extends Service {
-                     IOUtils.copyFolder(mSource, mDestination);
-                 }
-             } else {
--                log("CopyJob - " + mSource + " is not exist! aborting...");
-+                log("CopyJob - \'" + mSource + "\' does not exist, aborting...");
-             }
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-                     CopyJob.this);
-@@ -1092,14 +1073,14 @@ public class JobService extends Service {
-         String mSource;
-         String mDestination;
--        public MoveJob(String _source, String _destination) {
-+        MoveJob(String _source, String _destination) {
-             mSource = _source;
-             mDestination = _destination;
-         }
-         @Override
-         public void run() {
--            log("MoveJob - moving " + mSource + " to " + mDestination);
-+            log("MoveJob - moving \'" + mSource + "\' to \'" + mDestination + "\'...");
-             File sourceFile = new File(mSource);
-             if (sourceFile.exists()) {
-                 if (sourceFile.isFile()) {
-@@ -1109,7 +1090,7 @@ public class JobService extends Service {
-                 }
-                 IOUtils.deleteRecursive(sourceFile);
-             } else {
--                log("MoveJob - " + mSource + " is not exist! aborting...");
-+                log("MoveJob - \'" + mSource + "\' does not exist, aborting...");
-             }
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-                     MoveJob.this);
-@@ -1120,18 +1101,18 @@ public class JobService extends Service {
-     private class DeleteJob implements Runnable {
-         String mFileOrDirectory;
--        public DeleteJob(String _directory) {
-+        DeleteJob(String _directory) {
-             mFileOrDirectory = _directory;
-         }
-         @Override
-         public void run() {
--            log("DeleteJob - deleting " + mFileOrDirectory);
-+            log("DeleteJob - deleting \'" + mFileOrDirectory + "\'...");
-             File file = new File(mFileOrDirectory);
-             if (file.exists()) {
-                 IOUtils.deleteRecursive(file);
-             } else {
--                log("DeleteJob - " + mFileOrDirectory + " is already deleted!");
-+                log("DeleteJob - \'" + mFileOrDirectory + "\' is already deleted.");
-             }
-             Message message = mJobHandler.obtainMessage(JobHandler.MESSAGE_DEQUEUE,
-                     DeleteJob.this);
-@@ -1144,7 +1125,7 @@ public class JobService extends Service {
-         List<String> mToBeDisabled;
-         List<String> mToBeEnabled;
--        public ProfileJob(String _name, List<String> _toBeDisabled, List<String> _toBeEnabled) {
-+        ProfileJob(String _name, List<String> _toBeDisabled, List<String> _toBeEnabled) {
-             mProfileName = _name;
-             mToBeDisabled = _toBeDisabled;
-             mToBeEnabled = _toBeEnabled;
-@@ -1152,7 +1133,7 @@ public class JobService extends Service {
-         @Override
-         public void run() {
--            boolean restartUi = false;
-+            boolean restartUi;
-             log("Applying profile...");
-             // Need to restart SystemUI?
-@@ -1201,7 +1182,7 @@ public class JobService extends Service {
-             // Restart SystemUI when needed
-             if (restartUi) {
--                synchronized(mJobQueue) {
-+                synchronized (mJobQueue) {
-                     mJobQueue.add(new UiResetJob());
-                 }
-             }
-@@ -1214,7 +1195,6 @@ public class JobService extends Service {
-     private class LocaleChanger extends BroadcastReceiver implements Runnable {
-         private boolean mIsRegistered;
--        private boolean mDoRestore;
-         private Context mContext;
-         private Handler mHandler;
-         private Locale mCurrentLocale;
-@@ -1229,12 +1209,7 @@ public class JobService extends Service {
-             Intent i = new Intent(Intent.ACTION_MAIN);
-             i.addCategory(Intent.CATEGORY_HOME);
-             mContext.startActivity(i);
--            mHandler.postDelayed(new Runnable() {
--                @Override
--                public void run() {
--                    spoofLocale();
--                }
--            }, 500);
-+            mHandler.postDelayed(this::spoofLocale, 500);
-         }
-         private void register() {
-@@ -1253,9 +1228,10 @@ public class JobService extends Service {
-             }
-         }
-+        @SuppressWarnings("deprecation")
-         private void spoofLocale() {
-             Configuration config;
--            log("LocaleChanger - spoofing locale for configuation change shim");
-+            log("LocaleChanger - spoofing locale for configuration change shim...");
-             try {
-                 register();
-                 config = ActivityManagerNative.getDefault().getConfiguration();
-@@ -1269,13 +1245,12 @@ public class JobService extends Service {
-                 ActivityManagerNative.getDefault().updateConfiguration(config);
-             } catch (RemoteException e) {
-                 e.printStackTrace();
--                return;
-             }
-         }
-         private void restoreLocale() {
-             Configuration config;
--            log("LocaleChanger - restoring original locale for configuation change shim");
-+            log("LocaleChanger - restoring original locale for configuration change shim...");
-             try {
-                 unregister();
-                 config = ActivityManagerNative.getDefault().getConfiguration();
-@@ -1293,40 +1268,7 @@ public class JobService extends Service {
-         @Override
-         public void onReceive(Context context, Intent intent) {
--            mHandler.postDelayed(new Runnable() {
--                @Override
--                public void run() {
--                    restoreLocale();
--                }
--            }, 500);
--        }
--    }
--
--    private static class LocalIntentReceiver {
--        private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
--
--        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
--            @Override
--            public void send(int code, Intent intent, String resolvedType,
--                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
--                try {
--                    mResult.offer(intent, 5, TimeUnit.SECONDS);
--                } catch (InterruptedException e) {
--                    throw new RuntimeException(e);
--                }
--            }
--        };
--
--        public IntentSender getIntentSender() {
--            return new IntentSender((IIntentSender) mLocalSender);
--        }
--
--        public Intent getResult() {
--            try {
--                return mResult.take();
--            } catch (InterruptedException e) {
--                throw new RuntimeException(e);
--            }
-+            mHandler.postDelayed(this::restoreLocale, 500);
-         }
-     }
- }
-diff --git a/app/src/main/java/masquerade/substratum/services/MasqDemo.java b/app/src/main/java/masquerade/substratum/services/MasqDemo.java
-deleted file mode 100644
-index b00d6e0..0000000
---- a/app/src/main/java/masquerade/substratum/services/MasqDemo.java
-+++ /dev/null
-@@ -1,137 +0,0 @@
--
--package masquerade.substratum.services;
--
--import java.util.ArrayList;
--import java.util.List;
--
--import android.app.PendingIntent;
--import android.content.BroadcastReceiver;
--import android.content.Context;
--import android.content.Intent;
--import android.text.TextUtils;
--
--public class MasqDemo {
--    public static final String MASQUERADE_TOKEN = "masquerade_token";
--    public static final String PRIMARY_COMMAND_KEY = "primary_command_key";
--    public static final String JOB_TIME_KEY = "job_time_key";
--    public static final String INSTALL_LIST_KEY = "install_list";
--    public static final String UNINSTALL_LIST_KEY = "uninstall_list";
--    public static final String WITH_RESTART_UI_KEY = "with_restart_ui";
--    public static final String BOOTANIMATION_PID_KEY = "bootanimation_pid";
--    public static final String BOOTANIMATION_FILE_NAME = "bootanimation_file_name";
--    public static final String FONTS_PID = "fonts_pid";
--    public static final String FONTS_FILENAME = "fonts_filename";
--    public static final String AUDIO_PID = "audio_pid";
--    public static final String AUDIO_FILENAME = "audio_filename";
--    public static final String COMMAND_VALUE_INSTALL = "install";
--    public static final String COMMAND_VALUE_UNINSTALL = "uninstall";
--    public static final String COMMAND_VALUE_RESTART_UI = "restart_ui";
--    public static final String COMMAND_VALUE_CONFIGURATION_SHIM = "configuration_shim";
--    public static final String COMMAND_VALUE_BOOTANIMATION = "bootanimation";
--    public static final String COMMAND_VALUE_FONTS = "fonts";
--    public static final String COMMAND_VALUE_AUDIO = "audio";
--    public static final String INTENT_STATUS_CHANGED = "masquerade.substratum.STATUS_CHANGED";
--    public static final String COMMAND_VALUE_JOB_COMPLETE = "job_complete";
--
--    class MasqReceiver extends BroadcastReceiver {
--        @Override
--        public void onReceive(Context context, Intent intent) {
--            if (TextUtils.equals(intent.getAction(), INTENT_STATUS_CHANGED)) {
--                String command = intent.getStringExtra(PRIMARY_COMMAND_KEY);
--                if (TextUtils.equals(command, COMMAND_VALUE_FONTS)) {
--                    // update ui, dismiss progress dialog, etc
--                } else if (TextUtils.equals(command, COMMAND_VALUE_BOOTANIMATION)) {
--
--                } else if (TextUtils.equals(command, COMMAND_VALUE_AUDIO)) {
--
--                } else if (TextUtils.equals(command, COMMAND_VALUE_JOB_COMPLETE)) {
--
--                }
--            }
--        }
--    }
--
--    // demo code for building a base intent for JobService commands
--    public static Intent getMasqIntent(Context ctx) {
--        Intent intent = new Intent();
--        intent.setClassName("masquerade.substratum", "masquerade.substratum.services.JobService");
--        // Credit StackOverflow http://stackoverflow.com/a/28132098
--        // Use dummy PendingIntent for service to validate caller at onBind
--        PendingIntent pending = PendingIntent.getActivity(ctx, 0, new Intent(), 0);
--        intent.putExtra(MASQUERADE_TOKEN, pending);
--        intent.putExtra(JOB_TIME_KEY, System.currentTimeMillis());
--        return intent;
--    }
--
--    public static void install(Context context, ArrayList<String> overlay_apks) {
--        // populate list however
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_INSTALL);
--        masqIntent.putExtra(INSTALL_LIST_KEY, overlay_apks);
--        context.startService(masqIntent);
--    }
--
--    public static void uninstall(Context context, ArrayList<String> packages_to_remove) {
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_UNINSTALL);
--        masqIntent.putExtra(UNINSTALL_LIST_KEY, packages_to_remove);
--        // only need to set if true, will restart SystemUI when done processing packages
--        masqIntent.putExtra(WITH_RESTART_UI_KEY, true);
--        context.startService(masqIntent);
--    }
--
--    public static void restartSystemUI(Context context) {
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_RESTART_UI);
--        context.startService(masqIntent);
--    }
--
--    public static void configurationChangeShim(Context context) {
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_CONFIGURATION_SHIM);
--        context.startService(masqIntent);
--    }
--    
--    public static void clearThemedBootAnimation(Context context) {
--        applyThemedBootAnimation(context, null);
--    }
--    
--    public static void applyThemedBootAnimation(Context context, String fileName) {
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_BOOTANIMATION);
--        if (fileName != null) {
--            masqIntent.putExtra(BOOTANIMATION_FILE_NAME, fileName);
--        } else {
--            // nothing. to reset to stock, just don't add PID and FILE
--        }
--        context.startService(masqIntent);
--    }
--    
--    public static void clearThemedFont(Context context) {
--        applyThemedFont(context, null, null);
--    }
--
--    public static void applyThemedFont(Context context, String pid, String fileName) {
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_FONTS);
--        if (pid != null) {
--            masqIntent.putExtra(FONTS_PID, pid);
--            masqIntent.putExtra(FONTS_FILENAME, fileName);
--        }
--        context.startService(masqIntent);
--    }
--
--    public static void clearThemedSounds(Context context) {
--        applyThemedSounds(context, null, null);
--    }
--
--    public static void applyThemedSounds(Context context, String pid, String fileName) {
--        Intent masqIntent = getMasqIntent(context);
--        masqIntent.putExtra(PRIMARY_COMMAND_KEY, COMMAND_VALUE_AUDIO);
--        if (pid != null) {
--            masqIntent.putExtra(AUDIO_PID, pid);
--            masqIntent.putExtra(AUDIO_FILENAME, fileName);
--        }
--        context.startService(masqIntent);
--    }
--}
-diff --git a/app/src/main/java/masquerade/substratum/utils/IOUtils.java b/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-index 06b5260..2f697c6 100644
---- a/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-+++ b/app/src/main/java/masquerade/substratum/utils/IOUtils.java
-@@ -1,6 +1,28 @@
-+/*
-+ * Copyright (c) 2017 Project Substratum
-+ *
-+ * 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 2
-+ * 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, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-+ * Also add information on how to contact you by electronic and paper mail.
-+ *
-+ */
- package masquerade.substratum.utils;
-+import android.os.FileUtils;
-+import android.util.Log;
-+
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
-@@ -12,8 +34,6 @@ import java.io.OutputStream;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipInputStream;
--import android.os.FileUtils;
--
- public class IOUtils {
-     public static final String SYSTEM_THEME_PATH = "/data/system/theme";
-     public static final String SYSTEM_THEME_FONT_PATH = SYSTEM_THEME_PATH + File.separator
-@@ -31,12 +51,12 @@ public class IOUtils {
-     public static final String SYSTEM_THEME_BOOTANIMATION_PATH = SYSTEM_THEME_PATH + File.separator
-             + "bootanimation.zip";
--    public static boolean dirExists(String dirPath) {
-+    private static boolean dirExists(String dirPath) {
-         final File dir = new File(dirPath);
-         return dir.exists() && dir.isDirectory();
-     }
--    public static void createDirIfNotExists(String dirPath) {
-+    private static void createDirIfNotExists(String dirPath) {
-         if (!dirExists(dirPath)) {
-             File dir = new File(dirPath);
-             if (dir.mkdir()) {
-@@ -90,7 +110,10 @@ public class IOUtils {
-     }
-     public static void copyFolder(File source, File dest) {
--        if (!dest.exists()) dest.mkdirs();
-+        if (!dest.exists()) {
-+            boolean created = dest.mkdirs();
-+            if (!created) Log.e("CopyFolder", "Could not create destination folder...");
-+        }
-         File[] files = source.listFiles();
-         for (File file : files) {
-             try {
-@@ -172,7 +195,9 @@ public class IOUtils {
-             for (File child : fileOrDirectory.listFiles())
-                 deleteRecursive(child);
--        fileOrDirectory.delete();
-+        boolean deleted = fileOrDirectory.delete();
-+        if (!deleted) Log.e("DeleteRecursive", "Could not delete file or directory - \'" +
-+                fileOrDirectory.getName() + "\'");
-     }
-     public static void setPermissions(File path, int permissions) {
-diff --git a/app/src/main/java/masquerade/substratum/utils/SoundUtils.java b/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-index dda38eb..73999ce 100644
---- a/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-+++ b/app/src/main/java/masquerade/substratum/utils/SoundUtils.java
-@@ -1,9 +1,25 @@
-+/*
-+ * Copyright (c) 2017 Project Substratum
-+ *
-+ * 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 2
-+ * 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, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-+ * Also add information on how to contact you by electronic and paper mail.
-+ *
-+ */
- package masquerade.substratum.utils;
--import java.io.File;
--import java.util.Arrays;
--
- import android.content.ContentResolver;
- import android.content.ContentValues;
- import android.content.Context;
-@@ -13,8 +29,11 @@ import android.net.Uri;
- import android.os.SystemProperties;
- import android.os.UserHandle;
- import android.provider.MediaStore;
--import android.util.Log;
- import android.provider.Settings;
-+import android.util.Log;
-+
-+import java.io.File;
-+import java.util.Arrays;
- public class SoundUtils {
-     private static final String SYSTEM_MEDIA_PATH = "/system/media/audio";
-@@ -26,11 +45,12 @@ public class SoundUtils {
-             SYSTEM_MEDIA_PATH + File.separator + "notifications";
-     private static final String MEDIA_CONTENT_URI = "content://media/internal/audio/media";
--    public static void updateGlobalSettings(ContentResolver resolver, String uri, String val) {
-+    private static void updateGlobalSettings(ContentResolver resolver, String uri, String val) {
-         Settings.Global.putStringForUser(resolver, uri, val, UserHandle.USER_SYSTEM);
-     }
--    public static boolean setUISounds(ContentResolver resolver, String sound_name, String location) {
-+    public static boolean setUISounds(ContentResolver resolver, String sound_name, String
-+            location) {
-         if (allowedUISound(sound_name)) {
-             updateGlobalSettings(resolver, sound_name, location);
-             return true;
-@@ -39,12 +59,12 @@ public class SoundUtils {
-     }
-     public static void setDefaultUISounds(ContentResolver resolver, String sound_name,
--            String sound_file) {
-+                                          String sound_file) {
-         updateGlobalSettings(resolver, sound_name, "/system/media/audio/ui/" + sound_file);
-     }
-     // This string array contains all the SystemUI acceptable sound files
--    public static Boolean allowedUISound(String targetValue) {
-+    private static Boolean allowedUISound(String targetValue) {
-         String[] allowed_themable = {
-                 "lock_sound",
-                 "unlock_sound",
-@@ -53,7 +73,7 @@ public class SoundUtils {
-         return Arrays.asList(allowed_themable).contains(targetValue);
-     }
--    public static String getDefaultAudiblePath(int type) {
-+    private static String getDefaultAudiblePath(int type) {
-         final String name;
-         final String path;
-         switch (type) {
-@@ -76,25 +96,8 @@ public class SoundUtils {
-         return path;
-     }
--    public static void clearAudibles(Context context, String audiblePath) {
--        final File audibleDir = new File(audiblePath);
--        if (audibleDir.exists() && audibleDir.isDirectory()) {
--            String[] files = audibleDir.list();
--            final ContentResolver resolver = context.getContentResolver();
--            for (String s : files) {
--                final String filePath = audiblePath + File.separator + s;
--                Uri uri = MediaStore.Audio.Media.getContentUriForPath(filePath);
--                resolver.delete(uri, MediaStore.MediaColumns.DATA + "=\""
--                        + filePath + "\"", null);
--                boolean deleted = (new File(filePath)).delete();
--                if (deleted)
--                    Log.e("SoundsHandler", "Database cleared");
--            }
--        }
--    }
--
-     public static boolean setAudible(Context context, File ringtone, File ringtoneCache, int type,
--            String name) {
-+                                     String name) {
-         final String path = ringtone.getAbsolutePath();
-         final String mimeType = name.endsWith(".ogg") ? "application/ogg" : "application/mp3";
-         ContentValues values = new ContentValues();
-@@ -111,8 +114,8 @@ public class SoundUtils {
-         Uri uri = MediaStore.Audio.Media.getContentUriForPath(path);
-         Uri newUri = null;
-         Cursor c = context.getContentResolver().query(uri,
--                new String[] {
--                    MediaStore.MediaColumns._ID
-+                new String[]{
-+                        MediaStore.MediaColumns._ID
-                 },
-                 MediaStore.MediaColumns.DATA + "='" + path + "'",
-                 null, null);
-@@ -135,7 +138,7 @@ public class SoundUtils {
-     }
-     public static boolean setUIAudible(Context context, File localized_ringtone,
--            File ringtone_file, int type, String name) {
-+                                       File ringtone_file, int type, String name) {
-         final String path = ringtone_file.getAbsolutePath();
-         final String path_clone = "/system/media/audio/ui/" + name + ".ogg";
-@@ -153,8 +156,8 @@ public class SoundUtils {
-         Uri uri = MediaStore.Audio.Media.getContentUriForPath(path);
-         Uri newUri = null;
-         Cursor c = context.getContentResolver().query(uri,
--                new String[] {
--                    MediaStore.MediaColumns._ID
-+                new String[]{
-+                        MediaStore.MediaColumns._ID
-                 },
-                 MediaStore.MediaColumns.DATA + "='" + path_clone + "'",
-                 null, null);
-@@ -187,8 +190,8 @@ public class SoundUtils {
-         if (audiblePath != null) {
-             Uri uri = MediaStore.Audio.Media.getContentUriForPath(audiblePath);
-             Cursor c = context.getContentResolver().query(uri,
--                    new String[] {
--                        MediaStore.MediaColumns._ID
-+                    new String[]{
-+                            MediaStore.MediaColumns._ID
-                     },
-                     MediaStore.MediaColumns.DATA + "='" + audiblePath + "'",
-                     null, null);
-@@ -206,5 +209,4 @@ public class SoundUtils {
-         }
-         return true;
-     }
--
- }
-diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
-new file mode 100644
-index 0000000000000000000000000000000000000000..2588952b8172c791022bc815d725d1157d46d6f3
-GIT binary patch
-literal 2240
-zcma)-`9BkmAIIk^_5DzN3WZ@~MhUs*nqwPnwp@{7Ic7F<EHX#rOwl1K4Jpf9MI^_f
-z<eGC8a&JOPju|;R@O6CGfAD=iUhm`adc1#l|L}f1-ZvfXPfP8W-wyx)q%dfdv#_H7
-zhNPG<6ZDbc0D$PGBhJNUa&oevd4$8^2%9fozVP{cfk43Ja)r)~8#ky_YG5!8feAOW
-zNijlZ7$WHgh@9iF6o~d^4gGinM4q1Y6AnD^9XjSC2;T(uV1Ya;Ko@dBZn-Mw@^sHK
-zPPsl&w7oBfOqR9E(snFIU4CmH&pH!ZZWmsF3XL^5O98<w4}+DYl@7|n6v3{--TohN
-zlu+-W*S?otlSAvnsMYtqANRtky=K%dBl6nX+RDnxj~_plmX;P57x{Di>FH@McVcLG
-zY-ou4Wti8&`O@6l+t~cEs<x|=HCphj<Ieq>q+4~jZ?Ui4=?so)3W{oUC%<whz90rY
-zJ@1p_=uWqBNH<5{GdrDbYJ11T=C(OH6ON(7F*$I%M{w*D3mgNEeQJTrhhv#=Y=Jqp
-z2#zZ<!xo!iOU!Z4%<P_<*_E2wm6_SSFvGqu$CX*wms>hiSUFT!J60f^ULu_<ZColb
-zZWVS8WhitB4#jk{$#cgs&!HX=EpG<G?}b?1i!@42&`*xnPrPPwJrWj^sCOw%Cpzl{
-zjiC`zphhW$1eK|itJR6s5Z@{_LX|3^3hYw_@_wc4^-9UJ66jf}c(E4fS*L=3tK`$D
-z<k_O^#a8xi6H3XO4fJ9IJ=uz$Y=w)h$MBs%uWm)p9-#N2lFzV;@2C=it1Of+SB1z0
-z5xHPLt}2PAM&d!pJasY;>d(`l46Bg_Af!Ghxfe|2s1dtBgmy5YUDdZ;&9@yw>`?dX
-zfRZ{i$n9E`7KmR9n7~%?X%h<M)1XSI2NPIeLKTQyqe-gO@~<<X*1<wL5E0GJNp0SD
-zs)N!##xQt=4Lnx6G5T4Cmd_L-at;|IKwcG~Vi#@V7H#7e5my(jq6MZA0>iKctzf=J
-z03S->t5fFHDSU`OUyaOHCC`INb70au$Ztm7|C<_l3hXxl@*4&EY^9+xh1X_7bGARb
-zMo;sn(2I<q_Flo!X+pwMnKQGqQ}=}2&t&E^naqT|WKw|fQM`ezw!5AdL`nA0Kl>#m
-z#6(2^$$t?Ja__&11OOy-F(_-7DBk#pSf2nV+p)4czeL>PvV!rsejW>}!}M2v!IZ$;
-z9v-Y$tl%-at=(n=?u~voKC5vyKz)74ByGA;P>-m`&HWm=?Qr9L>dfROsaP<5nRBHb
-z2&Xq}@%&h<`B7h}y&~2tZhO^zU`ruIDqC!F6`=ii8Sk?7nx&{aF?MuyxBH=)BgB6F
-zoY{JN!JdTlh}09D-8DvU{GNld7w9LM3N;NL`{LKbr)bKD0Ahg6$=$0Fo%us=H*e%t
-zEXrqwO^@vA0qQ2$!zh_6yY;>Qe#K{TY4nlkLD$*nS3M}1jjLn#zQXz%mskt^#ZLXB
-zn09y3!n`lZ4(~juf^!M(@SA(Vk~1wg>wBbNza*cV1h|20l921<-2F(Gusc=;+u%*n
-zr*zcxdzWtNYyHR9d*WO}|A8D~P7{}Fupit~2b8yB8i+7tS<AkReYpDJs`>TqEYIgZ
-zqsGG*35K5E3Wa{h;R2j(@4G@r_jhA2_rz`I(&F9^*(VKrcHgp|UF(dQl)ToHHlMZ2
-zSou@N;7m8Un>we|>`;FC?<!=9#s9tr&YpVxqfY)?!x#-EP6;aK6}HaZEA(F~ij+*i
-z?Y7j4WsRPJ4j#5nljg+so(G^W0}eJd*OsSdhr|Q>W%dg6wO<?;xoS}|GM=MXT>(y$
-zMdXw?i{KM4(5y{E#_qmAn2voQIC)RKv{+t0yUO2z$wbl)ZY%e<C=?oPKN2&+9#W;Y
-zJ58@de!LYsfHBuqM3d!Bj7wLhiRXga6B$j=SPyA$p4;=oEeH0}Wc$P)ianS$4vc&Z
-zp6r_Z(<3n&(HngzAvB#P;+$fz3G*-|&&heki_Tzw#Qy0w9)#M8BO6a%KNUc*>ekCb
-zbxN#pOBz!mTko>(W|rs1N%1bPS~?~$R8q4S^6dZhjQ~mj3x4BsS#6{%{gV+^ZD!P{
-zpX8(j&46s0KQ;JQZQc3xG8Rz0z@k2MCniF%U1hGJmbw}4$3C-hc7vv`R${rH(q+BX
-zaI8Pt>A}R&<co`)ZpQ!-z~wih^I_f|U`825^ILzSLP?WEO~@lTqDA8D+nMSUHbpqQ
-z({+J6a>skCXXfQ{?s`plU6Anamy*Wo>wZU8Z=3?>iY!0KI)E-Jon}2tQ+T<62`Suj
-zQ{16MN4eC+kecH3l}=69{c8A(KmXIpuWO)?RydvyMThV+&_~%DjhwroMPjhXd0G45
-zf#DUw&=M5sT2ZT^6Bwz^%eiJC715Ucl`W9WFKu%oRjavIeM9RL?QF&AJ{d<8_|y_B
-zdFtJKXqDFcj~vCB|9<MjI~${wRSX>&aZUS9o?i0{*IY+_8a$?{NL2y^oQG|zd)a5L
-z+#+15p;c<*u*#WXjaA!(iqJ@G&F8janz3lY(ZYTGAFYf$Y{xfLk4O*8N?Xnc(qh&Q
-z-^XLvd=7I!UFU?qlpCE9xVfRJdh%s|0VCBD@_o7X*6oqqODJnS<u~tJhl*)+MiGxX
-zB~@}$>IZzM7771JSyC~ULAyN6_->9rq{t*wox?*6pgP&B1s&;_O4q%}u&N8A&7JSd
-z16$vqPxNfw>RX@9TvcDt>`bynpT7yqH!aEw+yTh-J>p-sg+s4{#~rCf%t@4t1|SdY
-ztZUHbvitCNwS0NkL&K_xPX|6bm3P%pqh`i#%)HQ<1@=zTv-hj9!UuMO##=Lr(|5%t
-z;&ZEAyNug3<sOKrbeKN3I)BQuel!U2U1{tv>GAFK<a2-U`3;HrQs}+m-Gd)ER)1eV
-M#>O61f$&cHA7ceLfB*mh
-
-literal 0
-HcmV?d00001
-
-diff --git a/app/src/main/res/mipmap-hdpi/substratum_masquerade.png b/app/src/main/res/mipmap-hdpi/substratum_masquerade.png
-deleted file mode 100755
-index aa94e2c00f99b9f2e2e1889c26955f85fa0932af..0000000000000000000000000000000000000000
-GIT binary patch
-literal 0
-HcmV?d00001
-
-literal 2246
-zcmV;%2s!tOP)<h;3K|Lk000e1NJLTq002k;002k`0{{R3VlzW^0008|P)t-sOlfg6
-zLYb0aoHj#{00000000000000000000000000J~0qo-k9A7ek#KM$bKN&pU3&HfI0;
-z0E8Am0002LB3sJJ%42W00002CAzLUjf8gNYt|3`FMTci`xxGkxtweHQY`1+hQ{Ug;
-z0001&E>Ip09?Csy0002r-`{g?v)S3%tx9#u%F3G{R<=!jqeOAdAzYgwSG>U2?Ck6+
-zH-``wH|px@G(w&=LzVyl030G!B`$I@L7j$%hCdS`X(2bCF;#1AbV5mWZf<VuM18^;
-zT<IZYI!dd<8(r8QV#6F>*&kx+CTZCpW9cGh>LqA9O04Q6XYECP>LX{_AY|-AeC<Yl
-zJ4>h79br34sm>i>)E;5zB4+C>ZR|C3$sAtoKzhd=U+g+|L`bLJA!STNqU}O_vLR<U
-zNT}gLcj!ZVJxilJOshUjp*=~KJV=o}OQOmoWIRiy)+A=nB4qFH@9OC4ydz@n?(V}K
-zUp-5p@$vCHM~^*Br94ci+9qeP99>sMp2HttJxZEBOrJqet~^MTvn69aOP#VLVm?l-
-z>L_YDMvSr}V#FX}!5?3;B4NHBUc((;!6jvlFM93m?Y1If#wKOCB4V{2Uc@0`N>8ig
-z<mAO7VmnKwa6pl<9$r{snY1ZpyB=ZMw#7Y3ndv5J+9YQ4^Yh3dVzMD%upM4nWUSfQ
-z-o+zhJ4>w7C1#@}X}BO<#U*6KA7I%dW<^hr<|b&_A!M?($VpeOmn(GD*4wckU&be9
-z+9hYIC2Zj$W!fib>L+R0B4u|rh~p$@!6IU_CS-s!gw1=OjFPlFN~)_SXIf06IYo<Y
-zc)w&niN3(ixHoXcENOQ)d*IgEWNe_-)!C3NVcMj;gE@szT9&}V&&EP_#Ux`zRItPz
-zU|MIfKTob}J&~U%aDOv_Rz#D-AYs-ZW4JVK&?jesGH*grui7YSLsGD_Y>k7A$HpjU
-zKu@m3V2rgaXp4%&z*2&2c)qZ<*rTY%#>(J=inx@^%X9z$07Z0CPE!DlgpCn03IYfN
-z0feHWqLGo21)>a*jf5VNqG^$hgyEiq7-%ejM&~8-gf?m?lx8@Ql9r`&E|%tv7Fvks
-zPBdJhZF*k>$<odM00lNlL_t(|0nF0_kSsYI$MN$GO7Fe1ZQCx}SGF5tTWj04cW-U;
-zY}>Z+>+Z}>x-)aux2#W+f0D!gCm9TX52L^Q(u0P-!8v$pkMBm^v47n;*XMTouG1O*
-z4hPbydhLP#Sh`as2c4i(Ime!JrO|lA5tp2y>cn)NEq5((F1|wr>90ET{cV(;J@-QM
-z!>`JHBKMI}B9Zt4y@B$iK1(|Hopg{s*EwglDNc57Zf@a270vZ<GC`Cxc+W-09ZPTM
-zvahx&sIai4<gMm<3Q8c^LA29)?@_8*>&{X;fJ*xMDk5+gNaZ|ox{h`X#{p6tL>#m*
-z`X+la+9~jBp)1r5k{kp|3(-!N7P<xuai|R;g`!8KaypNsAau-WpQFX{a#u~2%0VqH
-za}miwtdqk+a8NZWcU7sOmj1Wv_o2Z`+VQdw6gZ>@TvaItQ2%IzIC-znS5giOsU5Uc
-zqfnBA!W)1d{dP7Ogp_j3EChyjUO_I|AyByDYp2iG^WCg<U_Rw=EL2T71R5H00U}O#
-z*XM9J+>Rf--ho!XNpb`;$K9-j(mANHU54PaIUN$@cKqlydqpt@heH`4#%XNas#TzG
-z917(AKFe(7a&qFb6UYPsp&e9L*Dg8XFJ%YK_(dxp6a+2+Clf>%;t;5=xE4@{?4Uh=
-zRu0eefj|IGlNLJp17xwJaZu5_wNE_nBapMzFUI109xppVEp+_HO12TZg>j0Co_yLt
-zoXVL36Cgp7;ADhWk<D&VIVk#ahf{`}k55W3C=Q9|gNTI)gF>Ouh$ZO|sCewtml_%x
-zp52?2HY7ouA|1{`Ac%vOY!=EHj~17XJ?DSs#exDqaRjd{J;*>b0|(i9lMWzB`p{%D
-zWr>OdNS0WLX5gUiZhO)hCz2?3#`Yb2G=6xPg`iLj9AxWN9Q0b$<0*YAh8GP7!7+2z
-zG*F0P(8Pp2>7b~m^szYYa9k4$Q4AssvL_wn@zlJda;(-S22wM`LF@0O9JCAt5eI4C
-z(bf6+`CU_+D>6en>yVNTD%+u)^bl!kMa@VO<&>301i=i4KusB-HPp2UhH|E-ArS{H
-z^Bm={kc=RTA`Y@E4j{C_b1CP32KuEPyGFAj3ZgiUyE~+#3&7o;yKDQnMC^e0rKGr|
-zo#XDiz*oWP>AKZ+N8|Y~;P;)hij|zxlTk3jK^@_sha+>6>qsGHQ1PSRsntw&GMO*4
-zvp2|*Lr~Z$78PdT)c$!+29sum(~dxFKyiCA$`0zV<4m&cJFc?;R1}rVqk=(slOas9
-zZ5s@n_F6eq^cbYDlh5b7!a+Z61V;kx)ig~FGDu+u>FlIl+fHrtJq+z`pqQl+LsdTt
-z2X!;TNu_SWDJ9{^AvCV~7&J-_%If5xTX0IH<oEfZO2sNNgA`)mWV_^`2|!NYlQO8{
-zX7rdrZ-j$Pa?n`GEech<#(T^Z3W{)02M+b2L@fZtV)dS2&>Lb<m!0^t#TLcpGK$0?
-z1rC*FC;pHeDHQXvz=%fKN$cdGG1rMedt$*<b`o#cNq5LWKV4^0$Pf%72X)CoU*Ieb
-zA(a?3N(=%+J%h6(NCQK?fkWwW(XXT&+8c(91gAiVKo6G&)$8?l5~$UQa|E3UK?BnP
-z1*r*6Ff9pmA_#4{G*lM~rG=rE1p0pZWDweV<nquI8xjbN1e&~X?(Eh8wE4jB;J}p~
-z{&soo^xDrIL+1yNY}!Tywe`S}{*BA7{|F!b+~zF@HY~dXvY*ek%`0d*AD`9!1E~sy
-U8e-`#i2wiq07*qoM6N<$g6DV#^#A|>
-
-diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
-new file mode 100644
-index 0000000000000000000000000000000000000000..bd2ae71130d8d3756ebac2cd39d3e29fcd4555b3
-GIT binary patch
-literal 1848
-zcmV-82gmq{P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm000L6Nkl<Zc-rmO
-z1C%3K6vpwjZ8gKSnT%~4k;YuxX2!N{E8Sz;c1y>+`_)ZelAe0Cm0GLL`Hk`as$P=5
-z?EmYJzb;?8bm`r@cki~~$5;I0;`i;__hMODSqaeDvuA_<q!E|z-Mjb2($dnBqM{;F
-z;Ky|I=+Ror?}6@hC0z4Y*|B5COCny#%gdvU8#lhAJK%e#=bjaH--|4BzDkPOmEWNW
-zH9n>R^}nYtn+&Ax9i~$2z~Z=83V&2f-y+r`nK!Dr!lPKonk8xKj&UuZSKp7&#k^v=
-zG(HlEEI{6addKLhWi{W<ng4K*=2`s-79X2y_OfZ#5dHYf+ti~<nCdl|M%A0mX4RU`
-zVpWAE2~`@;WR)95RZ3E^;SA>PzLd^iC{o4GoW1%y+U#&0XkX!Q_<_aG_0WuGrkHF`
-zRF<25eEKa4RvV-mAd8m|(2gHHeg#!)@B=;L=<|f`!GHDDSF`x;YsO0lusNA-8fWc7
-z-75X0KfplzD>c6%XPtiZ$Rm&3naYdzPK|ibju!)1hKt5oI#aibKc#YfbmJYh!x%7x
-z&~|$&18!eu4^f;gND*s**1&R$pB9@jO5^S)4`AsXX}G;Rb*MH}^X|L4Ev9ql3w7fw
-z)E#Af0OAucAXx-smSV_!jL?b~W~X(e51#!<GGGSPX*G-1<nE=y!a`X*!VzC@6pS%2
-zKozdG76XLU7_unK!{I`5yfDn#jat+gN!{OEMMKB#gdKQmol7-aOr|wCd+6fDi-=!I
-zj+)=b<10qvVVv;+`tg7xCFGcVv;;#Ct{(7E2bu-@2F~SA)Z*e|Dk&+!*)JqlSBz*j
-zp1ut)A!n^0$XUBzJicQ6u^ew`03r>>gDGJ(Ml8Tn5b<Kb;um{~cqY#L(iMAf&PS57
-zE@JBpMf|W!;-UTo;{%MxL$;UYV#Klxw}@w}n|`c>s|Ku!?8aRW$3mxYc+`0O8X*2R
-z4M4Dwcrk#j#tVBsMkvSU*z8<Yykh2@^*A~|Qbpwj+h7VzNBjgx#5?OxN`1f~duI|3
-z!d_b^+Gz{X77GR$h-aDbSZ6xD^PqC(RRb<uxIn(Hqm(Cr0Yecz3InFXbc9b7@x}+J
-zV1%&S8l<gej7cRPauki;qk|iFDDN~JUQke=e0@(JeK7-f|9hPMfjIZWl>smY1EwK*
-zI!ulYm~3=_I-FTUaR*_CGDIt048Ut)bw)>g@U^4<ox}9)PxI;HFK1EXHUkm=1LFI~
-z?*2#^9UV|_ETX5zMob|`y{QHUh*+(7!4h>4wwZjActE@&lHsCN7%@Mq9R-~4A-bOu
-z4uhic^%C*X0p&(uz%;`HM6_mjoH@w$nF6#v%d3hPa?&v*-9<|>J5bvyUn6=LRjM}v
-z!LoQB0OOUr57P|{K%|jy;h-r<2VirSPedoAC*)wn0vx#()x%T?XI{h$iTH8MS$Dj#
-zCm;{kkB`d^(3VWEG@b{fx!5FImrLTuO5>gNCa{zT<UQPl^6XLPZJp^1oUnGH!#d$2
-zUf7xC(})*3(udD~loSt=c;f>Qu7VMYGZ=D2FJ8#<)0PacMm!H-t*Q?d14KNOk9X9Y
-zXnX*I<*XQD!4uJm7dB;hwBp&Ahx_pR{4d0Vfe$iywAw{DrX3%5Ak$Cl(%jN`_E1Oa
-z`N|I%F-0@pQP=PQj?{)HAe=Ubq~R<xYHx;5E1u2G?j%06Wbt6&lUP4o?Tjg?882*2
-zcT3}iV1@n&o(@w*Ja9Zr`Sk-3s10{tI4wqGO5h0`fLwVz8}i8OJV1;{iZ?c(u;%;3
-zs=h-7ue?tAPxh3BOC8G!sKS$NOZQ0P;lU29evPq-5p}1Dc$jK@fFQ=?Ki*v<986Ic
-z;gCF@9Z=p@<?-x|7ru(c3)49M*AJ*sUcrm6O2d<#&I-ul!OJ$Mxn=Qes=1qpFE;`V
-z4B%L81uwnEp)wb<gY2+8p6yEa$l_V#f%a6b)+E)4SALHH1=Zh+%YUJ-G+anL1+P@D
-zJe~y{{eF)DB3N7Aqun@G%OQ>U1L<Dc^pHyy&pvqOQ&qg70U}UW<+nBB1MGOFPZcg~
-zPjk!S*=TDoRs0__0P-I1t_l}UXZdCEY<HSR7SE=bx~k$04alqhZps7lUwoBgWzJy$
-zVx{&2Vl|2AI3sVPC#$}xA7Aa=s7h~ftW;KjW2MqO+5_%a4|u8e<dg^8vaUjx&3Fp(
-zXf;{5APW~X<3V-zpQ$`-v(lEzfNLCgX1=i65!`;b%Byq+Pead1Yk*E>d!=?}xT4Y(
-z9m`q%V4H*o%6qx?6u#>()|^C7R~)qc);phiL1{~6z~yi=*x`A2;jhIFc5dRf)UL~8
-mYj6CUxW+*I|JVPQk?UuaEz`=25ZodF0000<MNUMnLSTX&GmVe{
-
-literal 0
-HcmV?d00001
-
-diff --git a/app/src/main/res/mipmap-mdpi/substratum_masquerade.png b/app/src/main/res/mipmap-mdpi/substratum_masquerade.png
-deleted file mode 100755
-index bdc8a5d44ccfd5ea26d3dab204fdad8aae4549e9..0000000000000000000000000000000000000000
-GIT binary patch
-literal 0
-HcmV?d00001
-
-literal 2094
-zcmV+}2+{Y6P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm0000PbVXQnQ*UN;
-zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU(&`Cr=RCwC#SzBlvRT%!ynb}KrlTDgU
-z+N8NP0oxL-)uz&yno5f;2!d8$q#y{Q=z|D-5etGy^+71w7f~OSst<xfMcRfHM4=T5
-zwZ_JTjW#t+8j>_=HrKso=lGwQ*~!f8IkUT|w?Ys6nK^sTocX^0cK$N~xZD2mMq;s8
-z<G{ecJ$O&=IPgP5Lwgn%7w1vf#Kgo4cM=IQI5@axVPRo@Zf=fo!Fx6`GIEHI6(*@3
-z3n-@iC#}D~e^+a3YhON}uPywR$z))5c6K-3#ykm}*!$eZosrhBw8hlJyuYFbV8s`J
-z`9L)+`GPP}-2gMeh&7*CfAGQ>*t%fvFxO=J9LCmex;kp0d2<IKcx!xhbrs_A_}Sjx
-z-cL;nFc|@LN2vMh)SuIPSzfbD5y6EcCctj44eCQ8QMgvy1S56LdS6I@*+DV~SSJCa
-z$H5<c`9AQe%mM!VPeW6OpLpabc5k6*mY=!NpFDYT^VU;WCvuC)BK0u$o2@>BYe-_K
-zz8yx8kcfaAyodk?|IV@95b%Qo{Mpz5eD>uPNX(7zynNxr6^FLn1jfe30$nTV(%@aK
-zYkm?s6O*v$55dLeZ7>vVFWcWsf&b{#WuQtB(uux_qDU947yWkY^Rq(m677rp*dVgq
-zBI4yfo$b}0;0X-?Aptml?!|f>N_bj;`&X1I4hyWJ@E7LzJ>KQaK8S+QY>{jd9v%G|
-z9=LfGer(wRH)<M+=J2+qEd+1B-cu4hA%3CtXbIaIEC~S~q9MFSD21q^KpjdD`xJ$V
-z(usL(OfJAvzn_QR@d42b;O0yU{ur6EEaV1HIRT2`i5RNt1zf0F+a?i4GGT5RqCrYy
-zkkvHlQV-r7f!3uNh;{6Ork+mN(Os_-i2X1I$KM}-W3MpSzO@m~eK!anpZaADJZhfl
-zdai^(3GmEC(8n#L5YUiN5=o?O`P)9P0j=@olMT>vWEW^SkKl8UA8doy-nszC-|L5i
-z`x@c&nIXe%Q0uze5L6W-QixOvyiD-+;O2`}BZ*pcFV*c@*s5Bh2!5XqUJo|B2K)q$
-z9PWZ-G7G2srV)4;C1`<X1@ICVs;DsX0`Im+Eq5<U9dm;%^%i)0^ZB^KmUWAOQmb1)
-z*SrpoNWqs)fCDcVyhG!ZV6aoe8rW}tcE3;=iNrGgfG)+7I$lOXYh@TA=4&d5fd;BN
-z@U0foCu%Q?FJdLY+rg=bsIE2)9bdc(H65Frioll5X5maMZfcq6Bp3;!pcPnFe+h%z
-zumI=JU7`wj3RR#%@#)tfK1xb}x5|j+G>pFSIZO|a>VWwi?n<dt3O@Yg0t{bGprTdF
-zRR~L&z<CBzJoemDSxA(Lu#Y(c0_YyqNFs$mk}R)dWgf1T@4pVi&%6s`hxR~vI|gkk
-z2bX`HgxR@_nQ>Ih3Pyw@2@*6R=GTI`;(fs5cf$DQMxhG*d_`MDBEm9Lhs5nwlUHC%
-z-$nRlU<Tqf8x5DyGY)E*695|lT!gSRx>C@L2e!^2E~HeqcA1?BgK7j(kFlfJO>KLI
-z6Hpn2NM41fZ;V1)I%RHFm@cVP`^>R6cR5Y!LbPnq0^sgB9Q+0Z6X0M3&lW5Z(kL9c
-z9*0etlnI;)021rmLd;-Z|31J3&$|E?y8M+91QoRBZdSZrB$tQ7<8fdXP~&N19b&Tv
-z(NigbZ21Iup;ku?sX-ti+>reGBE?!SGL+e=;m`7_mdQ86*5oqmpT1rayjP=AjThVk
-z7vSJS=I+YLP+6?Ie!%c_Sb_<X!-1(0XijGYM-(S`R#6Oi#Dbp~`vK2Bv_!f!EMZu$
-z82noQv57bya{W$M0yp^e1hFU%n2iX!n$H8gb-2L{<;YGhzv^0=g`T-dOqqT;c($IM
-zm`MV-kl%UwG~LRJIEPSco${E_5C^7)^*qLiPXeA)7z3<?TiIFwtq~Rln{AqE#*u7%
-z10F%U7x>8xNuXWb*$LJa1Eux_+n65cmL<e#H%x4fBv`8F)|d^JStKwycxfr2Y-u!4
-z*I0w3bHG+Iz>=Ag<p#Gz4!DR*Z=#>86)Zc%C${c|N!=0&f5;%AgV#KZId2Q7sIh9S
-zJ2%yW(iX+q%I9GTL--+vc#sSg_7jOR?nM%779x^ex}sXh6wElZX#>z`jc2^@S5<Le
-z7Z!wuX9pa+v~yn1+_=lV$U0)cBm0m@2xvn@I?l{^pdJw&C<L>BWK(h;g85ugUBqtZ
-zNLh5WM7JW*YR_Y5kWy(%;{=ERy!C;1dA4j!v>d=iXJXS5fH5H&D{OQ!z47UO*FoLB
-z#^%(5%XX|X0y0oV4>v|U1IOpe`}X*^kGbE~X|sSA_=;Ufn5Du2X+*0Ikna3Vqy=7;
-z83U!jO9^OYJZQO6C?Jh^#p4^9DlG7f){HL1KwkWnB#^@MZMnO%zBfq!$tKU=#LGnm
-zL!u92G6MOD+~Oq-Sa~Ids@!%hRa(&uvgxHu`sWFOm5XM_S7t8XU)S`Ik19<>|FESQ
-z0%FN6r(hM!1OD+#7qTWREDw3S@((Y0oU7lPvcy)``e2IL|9;~({V=cPHOM3r{nvi`
-z;H6Az>V}&Hk$lVINxp@jM?ClOf2VPqETQm!FD-*$pO$`*Gv)u#a;7l2+wQi%xBVr+
-Y0LvOWjfh)G4*&oF07*qoM6N<$g35*9H2?qr
-
-diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
-new file mode 100644
-index 0000000000000000000000000000000000000000..c56d924e82226247414225514f6c666ec4002598
-GIT binary patch
-literal 2733
-zcma)7i#HRF7vC)Ou=efen@VhBh)NVnHY1Pbu?#&t!ZsTlNnT%%U&Bbz_bcn+oyWAy
-zBd^dTuW8;TN#0_Kd5g_A*2qu)!S9}P?>*;!&b{Z}^SSrj`}TGi@Lt8e0001NZDrxO
-z;|afYH)zN9UyR=Yq}J`RS1hqUfjg1^M-~<q!mtE7o!)@CjlK4GCq@4PbH{%F{=LaM
-zvaPMHp`qcF5u@KE;6H~=aEFh-N8j9m1Oma>*jTM`NR9RFIy?GPQ@{H9dIO8+HRp+4
-zDBrreIz<?+RNu`CM<>G!7A+#*9&wvf@!}nIAA))s*}UK>dCY7048uH;HYFn(lwlZY
-zUY*KQ_Lx)kUb2juSEKNh@x!WKBkGi4IC)rwjK=28BPhcN?~!BF`C~pUaN>xXcdHty
-z6+voM^=yF=T2zQFP{N`)4QX3~vdu?fOGY$(P&UtzHpNKWf~AX5^P0X$n<6wecSxBy
-zdLg7-$-Nnh?}T0-R>e>JuK(QFHmhHmh_q#+tRB5O>eK@zB5htQqQchJ*1oD!7te+a
-zs8e!Tjc;J?jZlwvCH#!4H_GPO7get*IJp<$<zW7_N5gwT+kbw3k)z~v&XV1MAa%fq
-z@01Aw4QjEv-?yom*<(KM5#;&fe*DJww}PLYw<@aQwC8EK4XaaH2#JC*e!E|C0;7Hy
-zfv1J#Pnk!|ThMT3_bOE=?&$O-Of);P>|=a^Gco-p>Rtx3J61p9Mrd7e>D!L3PpMf=
-zv*x#Z@~Rqq{?5@P_P4!%t4{VadDNgmehI@@sgtra{T#6Qrns_~P!ANgC=~e*OWmgq
-z?rChB*Q!o#)9`u)Cse8s3N2z@!U@aE%a66g==yOxM0=QJVy_e=oQ|$J?T50-5ekJy
-z7yoHH=3Sxek;AG-+h#8<ExCG^8{4vwn4~sM%4H&_N!9bJXHA8YyT#=SW7}sdD=QR2
-zIrCUx|G?;d$F!^FIhCqJW1CDbbjn|@Y)3q&TFcw=O2v801eA4ZyB6gk?#Zi@RHjvY
-zCBm~xgKUB;o0*w$_NuLK9yhmnl9T@dZC8rM=2UQokyei{*q2#a7n(Vin>m!DY}w?_
-ziK3m|)d_L5y9|&w1?}2%Qbq|VcNlSit)=`!Vz_4fdE@kJj@aH_)RNJ$T9A)S5mv6f
-zA=K6o5L$^x007yu))p78gpYjwbcf@1`p>r2K)bd!$E6>w?Hrd;&dr+JL0Q>~>*L#?
-z&BlYy1LQTBC^SC%mu-&P6Fb>0N+WM>qAtw+;m7Fdx~&<RJAq0Hzw&w%l-6KBD=Nmd
-z4l|=um(7pTLKl$<BF32w9LKd6pdQnG-=ch-Kc2rZlPk=gMCOH=&t)tZxS?f*HE{xl
-zvozJPE7e~sJ7)YvBz^qU33G;v&a}tT&4j^AV#%I3|M_1$uYX-ai#NiVB@lQt<^2uy
-zO?t4rNTrqHUTc3M5UptXtJ(O})b+*22gMK{^k?k>_AH<cI5n}~cH_xou9CP5p#PLc
-z0f;3zwsGr4dI9*ws+g#z^n(+B#BGwoEI=NMFJ$S!!kn!(fN+9#o4Ha7G8Ln+3I4k!
-zPSPL?$B4xjAl*PP%#^RQLcePj#?X034m$58EfL#zIZy6~3tK_&CwhEq^lD|$fDQYl
-zY#)B>VM+Hb@S+n<Au;45kO}(t{_4FXH<aHGh<4^Aa6I0%^ojD6If4g{%rAi^s}0BM
-zCYkWQ$Q~KxP<;JHJw^v!-TXZA!@s=r<F4|C&EiTHE@ybLEd4hx9e*2s(a@&;(hfA8
-z>BQidDmB((j!u|x>044*k(R>AZ8>ptbJ%^*V@6O=P}x!+O>V4k`)B(?w9Z2I`g%Mr
-zH<kD`tywRv6L(h!5|AU&JS4vfko(;9<+fzDmsNvn!V47ZLT;@Hr}qmle|-nyd%-}p
-z=>%B<fj7sx7Qa7x9Cel>*)UPw*2P2NPCp!=8p-&k18<B2sN<_&NTdQbn?LxR&3SEq
-zpGW7D;5xU`6vLO!if3mBFeH+C8K#so;VBl<?=S*(i8stXE&<m%rw1Mv2>KMKkzlUE
-zR%~pn`?Aj3esSnio$cT*eXu-Q=HzyfA%BVlFxVtRN*qClobb!(K}R~iIdy=t(jt>n
-z46fkuO>-P0ews@-pcMDOWV=O5EHo|Z=W?^opGZiHT<d0EEf@yEzQPtA7Vx<3YK4yV
-z)23i-nX{%?|6!9aR2;hQojq3}<BPo!L+c~LdA@`XX1(p)l%7=OAjzR~Wue=<`knXP
-zBTD*(fEfq!6nAfPyD9JE4F1$p*{JbK#)NV35m`PM-e<ZJxu2{FE6sJ=D9)YGMOFJR
-z@JC+V=qX2&BtL-RGC!m?gCYQLKCqsvVRdt5O70HojQ+I=YD(GsQs<NB2DLX5_5SQc
-zeW|glP%tWCCo_Pz^Iq4F66qpMWaQoDJ}`b0eV41ZJ)kWQY83(o4Pf8^*uk@eNy!8(
-zrpa^y=JHEB%_VUP_$Zzc5GP>8-Mhy-#N5u8oN{_K2rN7UF)@yG6!}boCJmxX<n~R{
-zxhG&??hI(po;~32{SO&_u#^<y1*Jd21*{g!pFrxMU$c(ZBUok`;z4|Ff^;{=_Hr$Q
-zj|gP$)y97sOlyu<W*y9AcqUa3f!=Iifv!|PhtyAzh?y{X5p(+Lgb!R#FW5Sl%SyJ)
-zWTYx;`@?FtLUTbGpM~hjzf7d}jbSi}sdG_x2V=0;hJ@&4c?SOms4hyEaHA2$4P3cq
-z+jbC#_U)sE4C&e|0vX>?fUNm%=#;U1NnT!i1vj!FM)%s<>_&*m`G}Xx@#6+^-?Y}J
-z<Jk)>*B=B!(TXuWG67Nw={gYItkpu7b%&>dzCEqD6dgzcN_!UN`aW`v%e@tHw>=D+
-zAZTqTT@bOJy=Ls^wM&VUK)pr`YBP^@O2A@nQ-O_rrqx_l;7S(;kqHagg$j~PPjauP
-zq*xkn1*=1S(DR=*ndhkRSXu=0vG9BIJvOVl+MyeR$nymlS8VM*$z4BB*KLm2pvH;{
-z{}Int7}L2(Ip*t};~y@68-qX~-sllaw04L@DWOW3`$9z3|65EwE$Rgc9l~k`V+^k~
-zwXuf01+23Imi&R7dbx-14t+9&9YuCU>OTvw);BviiK1^x44?*jP;Eh!DL1++Oo^UU
-z!KLYU(LS@qK*r9@R6~O_QQ?vL<KY(K*|=|j_M&IU*{nU?5RVdCh||tdHrX=-vNFC=
-z0f$77gxNCACk#v~TviJoh-ZOfy`!^4R3-uKiT>{sT05{IB@vT|L3Cj-{2m%Jca`cU
-zF5Fi?ziTrC^5^N_U4Ve~bq^!KwBwKxxv5LLL?iWbB?n|V)-(r)ru7(CG+jx?!%mSG
-zqT6Blk}2024(AeMj1=}czcyf#(vy5*RNm6Y6fCR)s|c=K%@eX!D!Zkbu7GpU8tDV7
-zXA;vDbc0uCJ1^ZyzcdtUh*DTfpo#*B86D(l?<f7e$w}>i%WO47jM|^}5Gfbkj{qrE
-z$1{FoLu}8CTEn3@%M4AKXK($K{(ulhxZS*q(p(<c0M;jS?UaYdMH`^bp%Z#J()*G@
-g#pMx)rC9*L*(#grgVnnJJI@zjZE0swW=4qpAGypcSpWb4
-
-literal 0
-HcmV?d00001
-
-diff --git a/app/src/main/res/mipmap-xhdpi/substratum_masquerade.png b/app/src/main/res/mipmap-xhdpi/substratum_masquerade.png
-deleted file mode 100755
-index 0f2b92b85724bc63985cfb6962e7b8bffbc71245..0000000000000000000000000000000000000000
-GIT binary patch
-literal 0
-HcmV?d00001
-
-literal 2734
-zcma)7i#ro+8y}MqzDn==iJCc6DLIv9=A6?qITT@=nX%q^%bOgs&FDa-gmh*OF_be~
-z4zuMjLNDc%L)fbvCTH2k@a_E%zUR8``@XK<?|GizeLv6rT+clZcPFL2YI^|yfRc-|
-zgQp~7{xvzE#1EWHk`U4Y4}`ZPf)F7={+}^FKOc?2P^nawQyk)Ax@3u&ZH~k*EiJKK
-z$XqU$#bTX=rVdzNQ$A#kJanuZ9xkD#r>Dop#_FshnJ#e+?$lQ{#Ky)(bB8y~vq7D(
-zD-8_|Y7k_pS%5Q=ii4Q{bRajY2Fz)Ov>Xons*Z)azHK>z;_DHHAy`Y-cO!bC!;oOU
-zZdeN#HK&DNaHQ~cLR-M-VXcr6-OynT+^{ANj>zR}hYoAwNA$z^`h-@Epb;H>n@(_>
-zc5s^(wiSYD)eLG?$NaP>S-QQ0xfQ?=??wy=FxNMht|gXk^o4U2zQGks*J3z=_7xm7
-zY8zR8B=Cbe`lGu4uoima-~HcMxxF3$2U)rm!kp7;4`1q053+Q9`x6$uzP`@W4f}aI
-za!@yvmfutl32ahFwI4yxXyIY5dEc}`zH8t<YlmF0f7PRhpFi;@pZ}9_<kA_(!Vc}=
-z4oFZJ7&EOGR-#Ls`aUzOPw3Xh@sANFo4T)F&pYc}T+L|D)e9Kb4Q<7wOpi^r6Q3lf
-zHV$i}Nzn!0?PK{4B&6NlD$US9`11v)_(F17ZxY=%=y^Eo?u(pHiDt2XL^YI@Hg|M>
-zdHR|?YaiE>Tg@We&o&4e;C46b;)vF1EInK$1YNBg{Mvwc0a0LsEUQ#U!4Sn!mJjlE
-z2@M)pE4SP>T^v_0q*en{rHLtWNT}4nEG{mlpNOWK-IiQ5%I+n?o1SbO&om~&T(ehK
-zSE1(~aP{#OU{rQ~Bit=(VPWAizTC<!-_q$3*C5m@h{4vv`e2zAM*<zZDy-b{mY0`9
-zG37b>5d(vx_dK8Z*k@O11zEYi41s6fxLoLoX4D+TJ9<}~bxel2JZ(Q3`WTr}YZ#W}
-zoK&Tat=7X?Bg<xHW_&~H8b6HNyJln;{0(<6g(I>n7{iv%>9!tajxI%Zp5=BI%3*GW
-zxQ`RXlHN6n^mO+E9JB$-$Q#NYky1RQeW36tcw@_A-Kt+`{GK85@K|eo(Xm1=u*_Vo
-zTCc~{F)`XlQ&a%}&>0s8TkjaD{@z<^0ml39^4fSKG2RWVmD=zjM)+vf)OXyKc$MXy
-z7Zy8R-zT~o&N9W8vBsJIoE0%eM<BkXgSQ<-(V}e59Pe5>_0GiXTZPx+!(?CIE^Xjy
-zPl%`&%03)R?b!9cy?d=XL-ldnBo|jT!H(M!XPTz|1T&-i`6c7QT}TDWqm?svR0IR}
-zd&6EIM-N%bvy5*luslm__Vs5ISQ_G@9_`Ux{X<Q7k>H8i+8AOjO=@yZs(C_PaMp1P
-zz_$IR`Dv&=hJh+1UjYaN3(C&ut_Ac};o~`bmM593ZnLj<=V5YdA6!RP<qh&bHfwX2
-zWDVj42VH8mOdyT7Hb*!Zk4~PojPVZd)mLij`Wz4gxWbWva)d_K)&Lj<;BCN>S+!4&
-zmsj1do32m70`yK+gEV&1)q0f+{GFau4U<sl$}Nvt=rJ$QBpjZz8P^ZZA~t<g2f)4K
-z&nv;QDkuuz-k48GPts0a2h=c)b>n9z>wq=v_~B-d0s8GX_~5pKpB3O^+TDmlM*h$K
-z3LH)eA9V>0A596LCmsfmy6Z7q{b5^q^sQIlDD13g#&M({d$-Z*{>of(j9r;uh1j2O
-zqnL_BFOEP=uT3?86onIjA#!u#49$3lCOmM%W{vPq>%E~3KRED=344>biSFv0+5Yt*
-zLtoxd96+9~T5;md1Jj?u&tvV>IX2V&KbWcNRyViS<K)xsx(P~*&?ilH3`k@EN}&3@
-z^|l2yL5ZGv6AX>KdELHcaVlPA`vi&1d0&srcp)e5e(01BOqvEyeCxedQn1H5yuS$6
-zLsK=$5h^0G8;>7~`N3G3n;mpgQZm&}T_s!htl7&((kz;Vu-rl5>{OS?l=dF^McNuC
-zQKP$O)gRxyJ^tq}!rBiuvaW3EpE#fpxt_3}Ce^w58RGl9Vn6`7u1NPEk5{xe`<zh%
-zf>`*nySw{5^A?b@*s7wjdvC2BVt5D*dH%!4$2|1!y)E-_GK(-kh~OlNZ&`Kju6=}z
-zC$3B>%J`U<`xc4tn9h>eQuw#|$ij}p&evIcrW!PX!K{*LLvONd8L9rK$Nc=nd+6rD
-zC(|b^9xc)Nz;rrgyX2w)9O!3GBUcjD#f>2l*7a!<&@xzKNK-5XCbrXmeNqVCKI&I%
-zKF_#V9@wxU=9@MxK{!JkGzZxa>J87nyD!vEi0AmnESS8Yy>}9ECs?C~I(%S7CA{=%
-zHgRiQe%vnYlG~)|q*1rCp${lBTQ9{gXlwdzPy8R6F}#WTA10^lAr&`xUYYBJ%l|z%
-zvArR;lNh`6UBuK{RP+Qzs!L9Il@NAukf$&kKSI$-SBnPt%&fGh5EvxWl_uT^wr0Yf
-z8yZhl;6A)pc{{zieoKX_G!ji&+1CT~8%k(KOd|spUX}_?L-}YkfBgsT5N_g+zAqQP
-z=#xA_o?)W&`}Zp)9aLIDQj5{)fmCekM}QD+$0p5bccOMU3Hw&D+Z72BQ`{599x-Zl
-z9jk=m43%F;`6^Ksr~a;Kl!kL59~0N-k~4<Jk@qc6x%bD#-dR^d3I{o5OJHKx5a^Wd
-zQtg}1H${cgUG$bmrhSmGwH6TP{O@1RJT$1>MzJ1MYKR|8MSiAkayNF84?GBG4+T>4
-zY0l`~ytdh8)Wh_4I+SG0kvEh>L-xO)JUX;d%vt>;Z<;OB1kYK;f0!mzuFoa3T#fX6
-zRlaW)s-)VS_(QN{M24pHB(B&?<dOK?hjeA0mmvO=H03J?aEE?Q$e}~KmMAjWd6Ycp
-zGXAgC^{UP~HRMyI?$e3w8>YQO!cCj1VmH;pPu=sKhWz0JzxK+`CM*d;q}VM|SZUN|
-zzfSD2190#LNDhvp%04S_9`85UhLdl~(V|o*44*`uqAm`Elzs9d$MgEIygnewi$HiS
-zMZ8eZ)|V5&^GaBrlZmXc0CIm<m`#M36`?l0L6Dl7s~$beQhZOs%9G<Umkqbe0(X_f
-zy;6}_TcNiR=~#uhEER}`R9x!|_~><#<dIs>p&#S{rO%v4+NzlQQBvCykkOI}vw7Zl
-z(YJaDASrq>Nh$f_WeRhQN|%=8F~uIUc`;e+BGe(>Y!UK+8}f<zAG`u5`woboL5hBZ
-znajd6IiM^~yeMIAIWHi_xYs92r7k}~@^Ul3;m%v(_C&}I76C`iD4Xk@Lg1WYhn+0S
-zC-PXeEPoHuXr%TJGa0OgV$1yL3|WD4(i-tjRDkq<Y?vJp5%&-!#JVM^oh6s7&oZ(O
-zoLfAfz!~7xv8L0H85}QQ6jNXzH+9u}(ztxzo6JY0vSTtcECu#?kdO?$_6~7M6K+D5
-ztM9uIS8S2Rc>NHwTeAg)`CQHdB$t0}KbV&ja3jU1%eK{;Y6OryYm*~@?6D5&KHa9g
-k%R)j7pLcCf=X$&cp00MSL1V2}B)>1f#nIiN%np<IKY)He6951J
-
-diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
-new file mode 100644
-index 0000000000000000000000000000000000000000..69011b70ae30ed7fd659f01e182e8029baaa1e56
-GIT binary patch
-literal 3874
-zcmb7nX*3&J)OLtAC_-<Q5|PAQV+B<bB&LWdMQ25bxwI5bs1|7}Xo*gQBBr7grEbk7
-zW*tNgHMe4pF->*QYG3#J{=NU+z1BWwt!MAE*R#)g_K%Z9aIzH_l@kR30OEEyE0?{U
-z{+|m2_f~f1!DIkHaEIXFX6+Cdwuk&*Eh;K%YisL&ooaKqseSxfb93{^$VfH*+F`K#
-z@bGXmKGx06ZE$eVTO9+}3{23lK4zYckVGIc%q(4(UUU%4)c+YS{3$MMW@aW$+p)gB
-zp2y=kxTUUH#j@nwyH$Nn@Z}xy7ssI99T1OBs2AG4kgFOvuIRmj@HNF(OsM*ERRTH`
-zJjNA$RuF#c);GAy{wVvW9SWXYCI4}R?}Uo~IE;inSv3wPb*Yfd9P-DN{4AU+C)5Ha
-zl>NGteYk3YYnInLVMKH1$}WU=my%B>oQQUOZfajqt4hKUDp3v<6Y7E03LZ6ZuXURn
-zFQ6VTU|ug2J!_P`x#~gPYJR5pvRW0N8YS-<1QCtTH?=QWf%~HEi^dd))sTy<Bkrd7
-zXIPgiltYP`0~3WWLOT?j*xWU9C@^<^j<U-@;qIdx%B@_hQTSYIw`vpXBs4zT)RvCI
-zJ?d8XH?>XefO-v?U#@~&G{ZB@9EwnOS?y3yltUR?=>kjfY?ZuQUSYGjL!Oy^&i3~9
-z(CE^qnNN0Ss|FOjSWwSi1<y63h(<+^R;WiG!Y34!7JK~8Je>3iPHKYt3?fLa%0AB_
-z?(6FthL%NW+}(NAfb&?!hyrm9O)gRie5M?jt9F?jU(Z(YTT=F4)d{Ur^i0&d;b>Dp
-z*NLuypC5sdrWAc%DS1yT`MEk2*J=8<w6RIpOjq{|V_X?a)z=DF@>wNd!IEO-L|<B3
-z3b<0lI2u)t45dG+>+?(N=^wj+3>{Gm7@!tiBDYQyHm%#<%+QUrCzOvNd`DFLKC1c$
-zo5tZzl_exKG+UBKKaBR91t;nFW)-j>YhA@TmYwo>`3VzMR?*gK6*1Vrs=0Kp>{Qyu
-z#)fxjGoR1j+}v~zXiV|Q-xJj;mpd`V<#0Hj!A-ASZ?_GH9NAMaGQ!2l6(FsF1qzA^
-zffWxN7uYX$P+J)`EC)v+jeevxgho2yhqW&%Mn_MY@$d5|FSvh6%;1dQq8IN?&VeF3
-zD~ua?Vr_)F3BkyA^SrP5ha!>Y7m{87D*B$COm>~TCpQunVpI1Vca0d*WcO*Zf$NxC
-zX3%xKTP3e~U_G?<FD1w2Mi>hwj9nOr6wI$X9Pg6*#CEy9vQqEE4cap5Byn)A2Q2Ta
-zj9uu6<**8tz=~!R_Z(@;=cI#RYlQYgaLl<h>3#hvEi*}S_XxRbzQK7V9Rt7T{SOB$
-zQhpSS)f*k4TKw*OY4ny~?T8m$h$gP6C*M486FyKLr6OCj%ycx|z6?c?x9&#IuNkhD
-z724`DN}h>%(okXL$!{`t7Uj?;Etj`>O0^W^gYH;&+Y7IYLK_;FxV!m}-ZYdLydHxQ
-zN*x`$PNuwo1^w8%xH8g%e9Nzct!ZcmK;z9L)g6L2;DisE(}x%KZ`Z~agP`hcNA`n<
-z9+5)iC$O~!*9$WRW6OZw)LUf@!x`Xj#{$;IUYMRy6acYc%jcSl_04a;hUC95-%J6M
-zFr!~1Z^D-u$P&x=IYVs@$9}2<Y$aasp<LgyQT8_a!N6erXH#779s9Npi{VPNZ7ccM
-zT3>?Db-UH(JB5ldTk)m&mWeaQe|%Gj11t)EnkiV47+;!GKIRR$wSm06vt%*W0Vc`&
-z*}d<2iXC9B@JnK$^WUzptF`)CWM@)PDO1dYZ~7>0@v`dn;o3&ho7TAvPIN5+C>b_M
-zm!E{B%(nC*4<x9=T@PF;amtyfCQifGh)lTUjLUf$ZjcgDwx{Y@zfwgwcX)cbOeSMa
-z)c!QnSG=_8|J(O>%2crjq{W;2UN7y!`WC16%N)p>E-%0e-|FTn2&HVpMyaE37d*6N
-z4Vuna-?kSscs%Ohc!~kGI^UEKC+ocRR-PJjsvHVuk9mX3h6-~0fcbk3zmM$|6LS6=
-zS*9`-b4qPi3cy1bS(~27MF~ImI4LArKodOK*RpJ;lfAE(PBnpNib)u`1y^o}a0TY?
-z&~ECID=d88p|kp~zzjmxAEQ7T$&>3;TJ-OR7!`Cl)6a&vG2OHY@zayE7&<&Kh|1G-
-zuiwIjb<AZ8N^P@a+JUKhr3?m0dyJ$<pYZ$raZ{Ia&+lF90{<t(NXBX_&NYv3JS(-&
-zuy%{tnqm|N!a6zzdumg5ZC1A#*{)B=+$GzAP8%Lh@&b-h0K?jEfZ+_f&9XEltMzSk
-z;rA~Kzs8S;08Ukyo^nm2g#Qw{)afH0<hO>|2gPzEUM^YA00%u}R$l2ndq)utNLHZ@
-z%*GJ%4E&j0GM{APU?v_IE9tt=pFOOhd0M?w)DPBBefBCAJRyIlcXj*pt%8%}gU{5M
-zG0K=lXdL0XE3ZAv={3=!hYSA_9V>Ar@_w{;qwV3&=&^X*N<sYLJb%pPZy!H4HcKQ<
-zDwN|?+xlXPFgZe~-5sJbbh&uu{@nH~{p0NELtRUQ-;$)#P_%_Dw7Mf|=W^D**fCGV
-z%6le<R1U6ej-rln!+PUPM92U{mn~s{<CYFmaLpUY4|;X5{d;TE*xX@I<ozwCN8t3;
-zKe6ec^{!uNNV4jqKS6l01r&?v<Og-*tc++PpNlYus>b8ZrVxsd!60WVnV(;vnrzAE
-zSC>Ys28;?JaB#A7aARybk2!o&;b8<9p}0*;2=FrWSv>ZQ+2~Uhru$7M;u(H-o@Vpl
-z$D8kJ8pBEluos&=F60@0CrFy)oOcPYZm})j%I>xRs0a!fob98i_Qf{_T}&+Nq@Epk
-z%^SLAruS=V+_TtIEcce0g@t5$p^=lI6?&MoBB0LydX8%eeK|kmLH+`yp!Oa*eIp$Z
-zsr@#!^0^ws#~EnB2pJeCN{wY#Zfitx)p^T63LOcMkk**<qa`%fKtJqMyhx1WFuwj<
-z+w<4tfy-o!D1RO$*Siuifp9BQM+#xCO9Z{rd-E4lI4UlFRJ~<=re?>tCvDU7-%Ce~
-zvuuCuYp1$5stcw`mX=F_ph5>f0okt`g+0r+-_ZLtc=h230ZG8(o|0ljt^9d)=c%lt
-zpxmM;y%LFn0s*9-7+rvOqLh!V1i=vf7H${Hy@Nz-e+j6Rg2ta(2@BiBuU&V36*^t%
-zmx2OFC+SbVx3N_3A)<^BaxhR0|HKyka1He6QJ_Zdcm(i}BQ*m20o5y$4jg}nF1`A1
-zr={(V%+s&;f{Fs$h-gW1NznK?i5}n}>mXR6OsptLv-D0h;XSoE0oDWqg$%fW?OC%o
-zrj9r+L%1S`D9sWA^ql{+{x~|b7gw&4I42;Cph)Hc!69(elYZQV6tqA$FkQJcrx=8=
-zl+5y(4Kr4@Sg$xy8Zx<V1AXabKLey|=PhCqm{D3i?2dmPEu5b-;?d%|>5p|iZ;)j&
-zsIn4`S%zPJ|Cn>Xy~Mzx3Se?>Pa)*`f*LG4P4mzQ^=z5}?N)IGT5`ANJJWDi+9wTF
-zYMTa?mq0>BsU}edTg--C>2BohXc7h;@a7sL{PRlvbQ|@w1!<Y_HD}v|eMvc)W&FqD
-zK&GZ0qo~`c_)xWxS8Xy@D5AVh7rBVYvBP8s^x=XEOCMd-ifd(=b>1jbI?mu1AOE=c
-zSIGQR%M}!?K<dLUD6JlZ=IBpx$ECiWlm3)Mi(zYjXSQe5ZocP-bj*PSERBVgyQRSR
-z*?i`#;PL(2KQL~!T$${iN5{Y>^(Uyb7#4;X{lJ+;%pDrK8zXV2wpbYI#uG~51oiPv
-zbB7e)0@>|D<1U@3T>zoN{{DRG)z27>Z6<^E(BGf%_C!F<2vvVEJqhNLtAIJSP!a71
-zO`?zx!)Kt1IISmhR-g62jm1z#>E!wuln4Ec5`vYkzlcGS39mUKf?*OSW;*{;%u+K!
-zj<e^YT4qH+DtD=(+@CZT4yMEUjMe*p#PG(pR;1ilG|&iWI`X7B<RKw-l@U$AqX4n%
-zCh2_l7z?2ev@nE&Il>=a{q8i6GGni<u2TFjy~%Z^st!~4DmiPii6INT`1dNM`2Mh*
-zC-V=f`s<jEE>Y!zRe)sjrL^!)s^}s{gU4*|2d0y;76I<bcf#0D$OPmN^lJ|VmY^nk
-zYcH!vWVUU{Aqk}Y1XOU`SzBy4^p%qR2^S3d-F_Z3p8TZruwan=9CQwMckfEtv)gNR
-zo~?@oRmnWMrL@pVwdte+CIZw5*`!xjQd3hGJO3l0oA{`i`R%dRY#TM4gDLyQTp`vG
-z=>LRCWCcse9ZRE(eZ-zTbgmzBg2%i|zRS4%2VRMhJh>MI<5xR<_DehKsh=+=K_33U
-zY{qF6kr`0ylolq*H;_BR%S;q^7FI{xI|7n+<OCK?P!llTv*)fvJbyw4ctfvx@_twh
-zHbr_b2G%WRQ8Rm{jGbj^{vsgh393HlnDhI8ggM&=poIylOBW`MGcMD65R8Dty#$?b
-zR;S4XOB{U&x|i9b)mf`cANh~KUPbVL8AgF6fQup6pceP#?#2^D?xkJ<=r@*UPvm0$
-z?aJyX#ES>Y?cZ7FM|2-@lN?Y1UPOmR-}oa_TB|kqBqb$*tYh2xkLb?oAoD(1C;XiN
-zja&(3Stz39NYaUMI!A<|U#oJOj7nj&0=?#q4Jf*&f830H)CkybQQkH|ma@JglW1yc
-zJosDsx)P6aAd7%WHG7>O%)I(GUJrzY2sNrl_{%Dv7>pQn(G!086Y>Sd))9DlJliJK
-zK+J`Fd8)2TuTu}if(XYjKjs#u_h@#&#-nyG6*lF2?d;*u<+?;bqw!JwJfk$PvQ(YS
-zIqPeaA6Rn2S7B@M9>%rl8p|&QMC@yRj@f7Z><=Fof91@L8-|w^_NZDvARlwi8LM`q
-zer(Z_`dh5bkC<WVUg|ZX-7<Ld)?D|EivVgFL`;|OYTW|=44X%Qolb|?Uj2EqcLZ|b
-zk-6cTx8`3L^E+P~R+P`}WRO;Uz$sncFE#*J?Bxr%83^IO538NElT{_wE8%|tlX4T;
-
-literal 0
-HcmV?d00001
-
-diff --git a/app/src/main/res/mipmap-xxhdpi/substratum_masquerade.png b/app/src/main/res/mipmap-xxhdpi/substratum_masquerade.png
-deleted file mode 100755
-index 42ceea8993a7d808ef8de18fa11e13bec5423b14..0000000000000000000000000000000000000000
-GIT binary patch
-literal 0
-HcmV?d00001
-
-literal 3894
-zcmb7HcR1S%_qVm`idjWOmfadvqxFr77(qy`@%GlN9kdih#4RN%Xo=MtH4=N2TD=s}
-zmKs;9LQ$fqJ!-|M+x@!lpTGZp=XuUK&+|F+k8_^$oMeKn#cx8gLR?&2zgc2U?T&T&
-zzkGuCSh8}(Q@FTzz7lW_W;p+lW90u!5fKr)ySx7<>IE+LoPK0yXXp6%c!O2sX^`C5
-z*jT64Z3hR3k&zKk6*NrUKVH>L`|=~WC|n0k&)2jYKm~Lg`qf}VE3hH6v$M2wHf?Qf
-z91aKPkhW=hyIa<!Ps!(!Rc())>m<ap2kiC=at&o&x}oGhrQo>^_c643%vSQ-P$c%q
-zyG<#0t;2n{%wjf>et>mFkG%T^!fy)h!&da0f_j_${$vW~-K*$rgkwx0e2ww-Y-J)F
-z>D!C++EDi2#QgaR>Twxg-wXHbMR>h}d7y0S46PqGD|w>{^#JZMTgAUY-mM9CZOc5S
-z5#rVez1FDU-h}krPzmT$_BFJsZdUYaLU=a8Jy2E*L+i?Qm=DUjY*OB%0qoi><6>x4
-zV`BFNz*QRI=zvuj3Rix~{Js&c<TAbvu*?ClnE<ZV)V=|*Dl&6uxMY@$vU+4_kq%%V
-z^r`q6TBP+ruD!b)`~>W3WR+)xD+4U^UqajgTr~^f+^z7(6FG<C($34cVk7Iq!^6XO
-z6RUHxbC!QR8J54+4RIfkci+^z)vn;y1#$Zu?iB>kZtEv5!Mx{S-W@Qn5x933(yI>a
-zvbD9Xiz!24?=LA4olNq^<vli0q%uYS8l-=baxf{bjiu<jiuC)W5%g5SovIaMV_uT3
-zL2iOMjYGXZD0sCZJZBKT_PFw=>VC`@EN_!sdzTyoY<0Jik14kDqatw`6J=_fzPh?f
-zyjhl~7SW~?l>Xr9-@df|!O0k%pmAm5Fs1A|sf%6Ov1JjPqZw{ZsGWrSj4S%SSMm!q
-zyn}VDj!%Bpi6KplP7E3aCTsZQm#`k54a3@0J9@Rup(Cmvzvwc(HS(;x>3V9lBW-(o
-z+cT(he}8{xXUB!ue$S0@JXD`HHrO9F78VxV13RAE-+eK5L*{sbb#B?&+H*;%n(*=n
-z@qrXh>2nJRi=RV6$7ErEj^01CXF=h%R%7Q}70Bdiqy5bNX=j%`YR<w`LVEe}=A3G?
-zG(|g*xHrdpBPG$I{UP4I<OuhpS2J0NpkMqk-7`NDC5|Md3*?SF+Ww%Y{J}&2o^v?4
-zfn2S$Jr}mLzoBn9U0<gpziM;OOE%GCuOdvIauSyNGD_kiNMbfS`=<4U-^2>~g=i|8
-zN0rm3b)xLsX!^iH>72q@e0GV_$Hp=X0r*Rj{iJnN_P|FQ&nNCBx2PPYrkom!B&}cj
-z>W6u-^!{I}qa!zbWd&;c6K<yW&y9QO)JJ=qe7!f}oR*4mZ?_nMiU<y2t$uvop6LJ)
-zjHj<O9p&>BXDGuGyF^Kyg^Q3`nJvArik(-9_g42po=FXT>xik*mijG1ZbNSmA9%$J
-ze~Va#iNnn!dke3e;g7Gdo!Obb*(e-c1A+tE9$V)Y7<zf{_@j|ny-#;c*3n)L;|J-2
-z=S>CHs|Q+tg6Bsl*x}lxNs){+tt927i<Xh*i!Xl)3>BfG=MuvX;;^FgSG#nK#xSvA
-zxo~9oh1*bmyNV4XlY~k--7j}Vcc?QXvO!ScL_XJ-i5$mp?WE6VySN46bLcm=9T<}6
-z33lwJ%eXWGCH`t4r{#pD;jdPzk?4h}y(K^C+Riics^`=uDBUd(zWC2|m8UV#1tYU5
-zM{Y65E$FzU*{H@tOR`n-z2+LOQL+{>1-UL=dc-qqhf=W$aRG%u`7)6+o_PmuA63WV
-zH&xged92?0RM3#;G4eM8E!vDytWm#Ge|@I?i|`hjZkd%<h&cUvZ0kYJ6-ChtGh0Fp
-z4T9Ye;;%$2>DO=mh4m`~=<Cln5Ls$laSnnJv<w)2<p;F!3gf`x<b@x>wCOu_egnMK
-zeKdvV^A|6PlFT74&CF4z(3SW~D|&JE1b@zguN;+wcXX}Q36G2nUcYMA7jcVvQA<(E
-zJmAH2tNhi-|559y(5wsde@A70lKB4im(s~)NVQ*Aw-<%DU?5nPZ!ViOxTE+j;hVp4
-z5tv-0RV|_f`RWXei_=fQ51G4b#-5zLT&3YS;@Z+xJ*qH5JUPdd^l^a6E`4cyM2d5}
-zeK`K5m?X?cB<}pe4G-Oz{;N<6PFkRdCHJ>WLkzmmT%D+c9bsCW(9qJ=%k0REOP4^e
-z7CD6HT5#Z|_`_9xAO?Lz1P&sGg_n)9akgEoNKWQdugy0>(6+RBf?(Q*Q~2j_V#8@Z
-ziyiI*JtUCXlhrvMVtFa{XTa*um^&Ml*NL`Tw5NC}S%Az!%|e<`e3lnkC4qkljx5}4
-zR0#CXUgl1)IAs?$1|h50o~erb<|yYNT34r;vSIOZ-c1A#K(UK3>_ZEIc4E|<)9>La
-zy`G1<)sjWR5aSBvGuTCL({-7*6h(cv(6|YtXs;)S&{oY{@|U1N%J$QHFjxDHna(qG
-zYio(p?nZ)&xPNW%@QX%N9NM6zD00>VDYe!))~ffrv&1Pg;hrRmq1)_N5|T?RRjBM<
-zd!8GSl=^eapB@Ow^bKU}nB(xye@h7Qklj9siI!hhk0N(~Ax`$B%kM9k-Ou<wM>9Z)
-z{i3h(lGaimlm2oGClR&hj@bDQ9h@LoY3f;8u&7Wl=t0yh2|-n!>fn?_(*p%lVh!wU
-zMl#?j(-8SJMDsc43frN%#U&z;4ao=EW|kTC<2(VeXw#7CMG54~_I?ztlIk?!vgD@0
-z%Kt6(?sIUpgCXsE2V5La5M_SfE2@r4wJ>gJtbMY1?cNpry+^)K<GdR98m4FOyQuI%
-z)07*|2ND|n6B`WN8hSd+C{GR52J%$k#z{huuS%j=z;l$$wQO6w-tJ5J8g#bL3nZBe
-z@1|e@a=HlyG*VRE&Dm?=863LUQ5`s>yYHmmuJ>4j>`hl;68I~T=euO;`Be=_Wz|ud
-zv^%5EHVcLVV`s)3i5!8IMnGxpuC&{leiQQi{dpsFfCy@)Ff!^oi&9s|Pl$M%p`EN9
-z_+CR^$5$Bq&g*CVF5wST1m_<f=4S6pO!^qaI5sIMwl-PY;bV4G_g`2L51m73W$!DD
-z`2MWZv%e8Xsbn%;fjienqI;;%D+SjL4m?{2c?TqyMN?%RU))y<eWO6=+vAeGe?pX>
-z2UYgDb8k?+V_yUWrK;%rh1DcpPkZ+cBvy2dPIUlt2$6Xfrc&vn&t$&Qb7jRrd5{#E
-zumE{r8o|ufJQ~2pUK`vFgxmA>Z=ny0Vp*6X@HC~W;{yWWX#6#%fOr;k6_WCW54Dtq
-z3ETI9z(U$ARw~acrjcsEMSlzkuEBIIwiunH4^kHSD&TTKQ8)@aEJhov+a;JaPTArg
-zyr!r?*Zk`QGnA8lR&o+dxQ+3jE*^~8hcSVJowL)tRmFwtFch{tZgCmCw9K#+OSKUE
-zS~EG>=ygSd5IWGyn2FLHM$o?Br~)Xxi_#9BGd@g>P_SjUL5hN!D^h0c4O3><H@7nX
-z**EZ0ypM<PVMW!*(3_Te^*6AUr~}o(!JW$@)TPMy;`l}8M-nYLL6Ehb`mBqZt<3GM
-zZ5IM6F^OJVIST6ms_DVckB?P!uQo0Gd)wy&=Pxn!E8Gc4`Gh{FSiNk@>OWrdje4T~
-zpu&5168f+`sH7HZ5J%^``*0FH*mWpe!XM=N9^&-#=W5_fULs3EFis2{UuHmh45snb
-zbuH3hsF3urgxS~gC#424I_j4Z;zfMv3#^$ZsilAg?KE4b`72$s8>5SdS6vN$-wZ1%
-zr9BX2z3D0Tw~ew@x|84K+7VF~C;}NQr$TZEqRa(!b*b9{px+sQo@r8npDDpU)MPlj
-z-wq-NzqAf$r#Bm<C8w!_Tyr3DB?>VHSNBcPzo#bi^{Zu5As-o8x_CA0P2#VgR%GIE
-z#UAT6@S~m&e+e7-k)Vi*R*{A{-9Dlu$1BUXScl<|iL1{Os1*-m&qx;H1h+;DSUT$r
-z7ZTTxB*mooRVy%3s~dAOfhx3|m(QLQ+ah_=x3;$CI-K{JQ@M%TR-ol>42ZW%M+VSl
-z?VPSDT1gO*S5u@4?J&k8xxGu&PeKP*{1p2E2i1Q)U%#Xb0IE>-hH7faTJkQTb{Fzh
-z9Jr9IEMvOgoar?q1qSL|NNcXUtfdDrS^o6f-#+{7XL>n~zRN!iahm1i63_Fu472kc
-z!PX&F|BF@12g|esH#}B0_>U^kq6&D^Sy=k*lBiw=Gy2F#45HRabqfzLLkpyrU}iDp
-zyM%4jt>^Zd^4>#%A}9`+?NHP=6p~7KcwFXRD-1~Oqm1d6=_X)9*OHG2M$15p%RZ9Q
-z6h}_Ml&`WXj#xkPm4z~8YYl4+%7Az8?(VaO(0Fkbi5sdSj_2m{-ZH6~Xy1{c9?nzi
-zdF~}t%kTTIjHg)bHp~94#Uzm^P#qs0j@8#RaEJm)y~Thi%2H*I4#8?nYG^;hc|}H=
-z=tjcc<cb32`2o-XvWVkb%%fS%&Kn&KR_7{V{o--PIKKjV{YS1nh}v$O+q{fI5}EjC
-zJa5%}N9XyAzN|l;5BX^7!AaYdaYnCznR6#=5>`uiT)TWkKiTkLiC?$&3iemk=byEy
-z9&be~Tz2E+@R!jr$+fwNZMH_dN=o-X!5?nSl!iYpQ01%jgd;1tz+~g;$s~B&J&>Pd
-z)W|ore`sY#o12?1IlOgC#45xRl&CJ&(tK7#)-T@0>vL`$Ln8wNqw<K{2{KH4B$7G9
-z_J+U(&~pZoB(9b$E_R`9Kz)IT9e=Fk-4NkKu+T+Ga@CWfEQV&)I<%J)KVg1wrsvuK
-zgN0!z3$&xwTNWZ)N%_~4CWsK!-K&g56Op@+jVv8`r;-d^sK@Ix!jT+hYS2@xytQ}?
-zZAY~%?9|;BmW^>8D41-}wb%OoAB?A6>9SmW9<zaAfE0gJ_waD%sgq3xuq((Is2%6c
-zK%<!}3_-K}#f_pDP<*7kjp~KXg({p=8cgbut(~`$YD5>cf008PHZciyes-c9`R@~J
-MX=ZC$Z*ndEzb5@DPXGV_
-
-diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
-new file mode 100644
-index 0000000000000000000000000000000000000000..4448e0b97e8333ae8b1ac5915a22ea9b33303ce4
-GIT binary patch
-literal 4947
-zcmaKwc{J4D|Ho%BQDkH-VkTp&ltTDe<~?>HqZMVBT~ZP;W`-8Bru0d|Oeurx3Z=|g
-zvV_oNC;Q%5!;IN}KIixU_nv!S_uTt>oO562p6BzNd+uX<JInq1WcPtUp#5j9%r5NC
-zwEu<>bT@iKvd(}&kZpV0OXjxzw{~~_X9NGwEa>OYpZ^a81O%j~zo@o}YHDg~HuO_D
-zc|A(m_%x99)dsJwm$baRTyn-m2lFV)B=D_Sa7jr?o|co{mDCTH6INDM78VwEBbiJ-
-zV?s7HHJzWIS5R~RV;0>Y>)fp3t#AFlQO;#R!L#wO>mb5&LD73r#oxfXs8QZ^QQ2=u
-z#di?lwV>$3Fvl+{`3@=j4(<Xd-@zl-2a(qs<=wt1U&mle22nmks(wRCK4{z5e@t=T
-zl)Rdd9*e5}0Jh{C%FD<m_nV@pflZOgh0>-Y9!(1FMmBGoRedT|t{dBzG$D4EZwzhT
-z4XN#(TTpSt-Q;{J!vbHf;98DwE0cFMv@J5QE-Xj7S15TJohz<X_NqX6Rw#Nbss)%`
-zEL%9@jXqaoU_%*@_b{}jG#qj+JM3a)^V-n*E!vihwj~+a<dhzEHnPqHu*C*ePiYFS
-z29_yC)>#JT3ICYK8`>5&BHRqm{;O|IF+7`LXqB#Sk&L#@L0e~hM+X|7B^y{iF|bGq
-z!%-R)+*?tO1&7anMqK`aaJiq<+@;|0M=y+`99WC+{EqUPn3!slcbio9OFtQ*ZIWwo
-zxqRk`_neAfkFqyW`@wIN&(f)odwTKX$m_jGuTLn?9M#}DC9hwHJ^YQHM#OxoQgCTd
-z@n$SB@|CWdT2Ypc1@)r5Yk|8pnnB|x;eXKgTre+f&EGg!lFhMCJq@Er5MI5ieuawH
-z?QPyY){G7@NI8owSTK#E+7Z70nEq7TK2qD3OQ~;e{gv|U!=S2P#S!0__)>-?;i^w%
-z*JH|0%uRQzY!ClzU$cxWrpe_<9~;Zewj0l9+xtffsh3=`>FqsjMDnh*Ha9od*VhYO
-z{`Cs}vMZ$MkgCjpocN%Uxw*NKk&(dgdhc6xzM<5`#U=kcw9MC?xsujFyQ<Z`bHVN+
-zNJLm=4@v?G-fO67c2EF*NLoihUE?NTqVy!sVLl>keyXOorp(S&uXt|qSAK8o?3tRN
-z&O*2%2n6pxYi4{YV(3pFET!p`$is<qDupE2mS*C=FP90q;wQAU%pINRD+2uEK5zTw
-zL_zBPRLx=RdOYYA>j^D27If+!YjA0D@=>HTM18CFn|jyA=s&(U!I+pZeT|BuAK|m<
-zQ1Bl1(x3C?x)gPRTrNCerXQxmc9Q|A?1mal*$|(sXZ?j1#J}%pntKzhuMBMYZr*8l
-z&>FdzVzmlv`l=>+xr*H*?i=;E3v9XND5U&jJPrOH)i2dMJ;&qL=kJ>owO<k*_I9db
-z+@fc3mloeA3e8aq3Kw@;c&xSheBm0($HO5?$qi~lRX3tEBs@CuZ&=6<C&~5<nEdj&
-z1$%zAZG=?H{Cy%@D(e}Wi{#LwhQ2N>$;rv=?{hVvGQ-FANxunENjj2fqtX(TBAf@a
-zq1)Klw5M@}_f__)zGc18iR{<dqnW!gwJAfoHmM<8qqKjV6L`GvSm^2rAC7JVw_egQ
-zim|>1HZ=n+xjEQpyX5VNPR}gxWbPl}=~q@}D3%CAo`R=&=CIzE-c2B<1tSlh2Y7t`
-zV|!YWC2>Qeqo|{e23jXRP0G6am?{Jc4Mc=L+Y)N!y6yjU<rMEA`9rvoA+mznoJPko
-zCBV1&22m$2Kc877oHqpjliUP;3<`N5KPf!UUHS6o$0alksd4;kO|}s-vA(|kqehB=
-z0=R*{H5C&yt1BdP>C+D;bfR=)2(b-2%}d>`_?DXgH?~4Imh%#9d&(3C4&c8KQZvJ3
-zY9ezD)!ZK`fNbsT^rP1VPVqFhD%yy)ePc@9h%dZsS^iRL4e^eE73Uo^qllYw8p9w+
-z@V48CleUkkk)Tuh0V-wSGF1-ZC%AkkPB3F{+a^_ZO6wGAgY=w<qS=l^O44}MOkyjK
-z15yF1UJ?WQtq7V(s^PWymMIO0g@vm@Ja`v*(F;b(fMslXF(iOWARXAn-34%Wjzb~{
-zI!HmVv?5Ht@-&>hMv|)a@IRI?rN=92);bN!P4CP1OP1}qVw~<Srf#wLFQYyfs#PVK
-zACjWze84H=kYl&RWvc>dPqCiLXNrfB5blpp{NW!Z+anbEiWIJHn_#jrBf$9yVs_PR
-zzL10rKw?C*8b2by9|EyA;33V$)N3b@n8p(+wMHPueDR@IQ1#1{5mqk*(h!nxt6z}F
-zpYKU)d4tg6IIg>Tb=H$6cs14-_r~SaS~O@l`Os-{n<eoPL>K>1SfHq{C#HXT8FVnE
-zTO9Ncoakornl@M(0)9-|A0D!bBHmph@ohuTO4IgbaqFNE9q_>)<CCC)0)x`4%(J%J
-z6md1bo%-r^OAbun4|gC%J{(@FM=Q8UakZmq%(tZyh4zUMsBL35_-(K&cVP6EDgY_#
-z*V5<r?_3MwDlj84Su#)fxJ1Af4}ifh@KtM#c7n9kBpTJZxZj~HGCF{(ztN(&CcZC&
-zMBqsiGC04X5CzV_azZ1xj81X0Q~z3A%E>GK_1@;OnFx4P&GClF0?vle5lE~=NN^m#
-zO@JunaTmwsuDQAvxa~=Sk=@l&CpHp!@e|vUps$tyM9mlvnjIUPY{B=xm<)P%VIk_J
-zh5>S?ae7-)Y;}$zz=Af+j>|yp?X!=DHKuNQS9XUINNp?1Nb-2gR?_g{@x;N@;vyOA
-z2;)&TwGe!HDT|BZbM|h6R$Z9efBw-uYDDWFn*{|ioWM-IYk7`MbH2O}%Pp-dXiRVF
-zs8Nvos^1j2?D@Cb2uNg^;{s$V6j0geg?8ZYfv%Jr(qs~$?i;MzF)*dF2sew>77;21
-z6bAhJN|GzNTHla*VtQlHB#X7?b)uOwk<3f?#Kg$}RpB?iy=b~;Y2R>n$-f$znR)Lr
-z#{d=PS6Dv#^kL(_UZK+Xpe;pwq*SfMNNVgUxoTnjJEACnFM?1Hu3nZUN=TwcNVX~$
-z$6s-*!MD+zh7P=XxY=LeYWb?yMkMXwgJnzbhS!_1Xkw<D2<@)jB7TGF(F1&pSTlsr
-z+br-(PIgW^2+iAXtc*B$;OpYTmY_v=UC6$p%PrbHrDE<a;aezByZjM;`ZVlBmNzy(
-z0t_^2%5rd-<J$*A?8n$L8UY`N{B|$sTr8Du>N4r(^2d^fNpnFy>l4GkrnjY#qDNX+
-zS6URfoGWo-J8rZFErBwbCdi(sk0&!N@Vy|}V{dUx2J}Z~aqP`#;xYEk>n~wtW3L5Y
-z!CF2@^Ur=Giain{@Itre3fsl`I6xEwUWMmHJ(DEH{vrqq_59AQe^1)iR|F}n+;J;U
-zl1aC~=(TY(RG9Drfsoqn@y=AD^YYKQ=EaIZ>Xq#1zA?gYJrHE|LF8tvS1~M35@M1E
-zyKk%=v4%p1FLc6{;&}xDQ=?8(;3Gs%B>1mq%q)PsKGBkAIfD<Sor2f=9q%&9{j6`!
-z=?(DOLh(cj`Lf1>R+LY`VLOGuqeLp*0b|wBGH}RwC+-$Rz!n{W*5>E-<a;Jtc=5ad
-zG_c`2F(=p!ZE$p!5Y}ecQ%J-o$s}=SCOia?n%+Rf{q{)g*5ch`E`Sbk#JahT)sD1X
-zBbkWeii(SGME>d_5ZyrFOHZhNBDhF?Gt^p+7hH~^>l^LCto*?4y+A#Pfz9ATXEga7
-z^JfTfF)aHx#3Y#YVJN?N%=t;DPrLVzuGlUrz&&EVS}kohk@{IQWcHbxRoNyA1mj3~
-zz;oatm>+ALC0(vRGZ|Elluf>C(F=*y!3VLcj_cr$wU)2Ndfp;VJuYRRt^^c%)Ib-7
-zLZ&OvrGDplf*-|VWfI=%GVgb;q#nW_i$4a#tTd<gPU9ur8H{uyB<b(N26q)NMvG_W
-zRiYM&b4Q@k?P*9{Pgt~%n8a_m3KNx<A-#zZyEEOWQQ{*}cGD5-HwSA%OnZ^sCM}IA
-zT}1NCG%jekYQg9NU;!(dIJ4UP^ES{&r!Sz8YE#4P^793V+~XqEH@}aHbH0vXwO9wb
-zr%of)uDz;6ydPv1#2_XlraRzYixD<zf;Dqq^eTK&cIo;*oqdxnW&n(gF(P+<M9770
-zd7((7JLk#L-9BBq?DOtZmLSH}f%?=mAkALr$?6QR^OdgKEi_2yK=7KECNQf3itHj0
-zw61mbq+ZT>FuHRZ0lsme?ki&WYUp1tR9jg#V1Z8st1_FLn@e23F1&;TjH*fkJx{JJ
-zUJSVw1s97GNn068g;)Yxk}yp|66Y9L+pK1?QA1jfRi1WIa)8|nofmgS15$rNg=oQ?
-z;~}f0OTq&WlU>5tEdOi42CQ<5OIyZsz-Rq9j5E_Isy7_psFy;03Wn02e6KipIWS<D
-z_5d?LOL`6U(TRpf35UzQcpC82%o|x>k>q}cDC@3qeJsgxr)zYhedY&)y$?-AZ)?2u
-z+T6q9Vvi0j&Y?W(?-Cw^v&kDdlX3V295w9I)v{3%f!IC#fOwK4=?_FZ6-f)=tyzH7
-z!S1$_d+63BiWPeyXfv?GW=2DkJk_hDqK4*$rAja;E2^sM1CwLkn3huiY`}qs<V4cu
-zp7q8$%u+-MJa8s8g+gZaMI`d;?+0ERXA1A{j%24O2vaxJpW^q7*xmp~TC>~Xem=eJ
-zGlVVmH2i11Bhq@jpU})fd4(K620uj?o}p-5<ox}<O+9HyURZb7kE>((7jf@Gq-%Jw
-z(9BG%(L%K%V@{yTosK<Dhyjl)kLhnSnf=N?sc7T=wH1AGfxgJ(5h3as9jX@1uA8CH
-z<3Pm%@SnlB1&Y-UL%_wFZ3FMd$qLmy7oui^(9w>p6P$N~en#>Lc-0Of`8nxiXIE@G
-z^)INC60-%ov0^Ulp*~-Kp+I!qaYFJr{0sQc%Xu;x)M=t=TQzJ5o3={7ynQ8xIzlw<
-zbgS-|ovL<K<8#@GA;$BBYeBTv({b|tz`3`4p40YSx!qy}T-ORpx#>*&j^=*pFQOcl
-zASX|E<DOyGS^SmgHcI&_J?zvta&-=|>N9GX<BuPBrixmiG;Px_j{|y+Y++II)#gWD
-zEm)hG|JcbYQiq!-=;KsMpByPgi6lOTeGx<Yok{HgC5+8XUc|DuQDa!$*QDQ*8U{2K
-zvJ5^D$z`)OZ~#|G@Cj>4S#b5B_L%-{7W3#j_b;9EN_cT*&xb1?eV^Xkd_a<|BL(Yl
-z|8}`~Vgg;%S$*PlbN^N1x%*HRhWkD2^o_l_2_vc0kxs5r3T0%wzZdHK!s+YF?gf-f
-zNF}S3;V_Jib~=uu#F1p-GZn6XY$x{p>q$4j$+GYPYW&~*_dE89hzV<x1W4i&V+QXz
-zkdIf3Sla7c$-VsFqyWKRJgGon7iHqFrbjm=+}y8BvOtr>`?3Ar{ABAdXD;Fv+4ux!
-zAp0G6M(~$TAoU{dY9uZ|+Zl+qW7&x2d+Rvh7LOB9x47EpSc&j_*0%)gsytv`LaK}7
-zH9!NdWxke4b_UKl11{+b_U*mSYY6loHcp(kD%Bs3uy1z?RAYX)!%dIC??^D;%VHRL
-zE0nY)O6w+Fd)46#(UXLYeu0&kaHCE}zJum3Y_x4ZTcX%(IG~YREbZIezqAedL)LKx
-zOv_2q&PkGZ7uI366i@4(+of8k=)M~cfcx@>|H9f0TFx`pdj*Wv3oNP&E76Y?-c2EO
-z>I}#e55^c#T<U(m#_*+De8bAtCLo$&Bw4?`lfmTC6E8sP7_^(!aSeR@*mfeA@)GJQ
-zBS+qp6y~$vt?&=Bc=XEeg5+vvbh2UH!4PYQ%{!#q@R~{}$>$^qoI_Gc8Iudq*e2Fe
-zweh*HTPVD-t!0F+$H9cD2zpb!ogaglngxp$6Y2Q6H?Flc;Xw^l;^Oe@(c39mM2V2+
-z=)LcxDsq<WI>)>A)=|S_;-+(<DY~R!e(<4P@7`Zr1KX#-^_Y7O3oaAshJGM#=a+-Z
-zH3~RARvkDFk%JG%)SgPv+F=uugh!n<V%C<4TqA8n4VOuD*?t4-YS{Dkb|}?-DQ*_}
-z0YT={7Tnr@9U`LN98K&kbC&~k3fiI3<MD96TJQ5u$#E%n8fvWHjb^dib;L4v4L&}N
-zg5ISB-|#NfdnF)3cDiuj#0@P2H+CIdzRZ%$1u+CoqlR-n2cNFK@a$Ndnurjyp&oYn
-zr`@aGKZmD#r$(nbbJ<mnKPXpZ6>By+M7eD*gx`33EJf-=!fpr`JZ?1wB<N?iT0M-9
-zCZ;`6{u?^|QvNgM-B8ADfux=SlbtnKl7mUw9m#lcDPJpqcTH>J9xR9F1iPKX*{o(V
-z41zVqle`H$b-OshZ>Uv~eoOYPJC_vRs3q)n#eNy{te3j+r)LiQ_px=>+|I1T#69-^
-E0A=T)LjV8(
-
-literal 0
-HcmV?d00001
-
-diff --git a/app/src/main/res/mipmap-xxxhdpi/substratum_masquerade.png b/app/src/main/res/mipmap-xxxhdpi/substratum_masquerade.png
-deleted file mode 100755
-index 53658674bdc6209cf4ada657cfa150bc21338d60..0000000000000000000000000000000000000000
-GIT binary patch
-literal 0
-HcmV?d00001
-
-literal 4966
-zcmaJ_c{J4B|DOeemeFDhGo(-{DqCS@kQ8b}8)Xm4GK!G&nMp+@OY($Lqoj#EmTX1L
-z*vrmXBFoq^#x`SO#;m`2&hP*4J@>xvx$paWujh5{ANPsVS-UOryW~M2(3aDuPB=?;
-z%7051Dv^GWY-11z!f|puZ|fL%Q=<8w1N=X4L4AFF{|~rv<3@UVMwP?erlzJAi|aav
-zuHD^hbr_vp>j3DRJzHL0E;4pE!Ng}<2YomZT2xf@@u=(Biz($7p02E{%+JqDWKK?w
-zv2~7(jSZbnN9cJip19Yr>uQUR-*NlTjcV?{5I&9S9>YkV`Q3gDoj`N@!bS}b#@_2A
-zIswB--}&ACOSS-GPr%6DfME$hJ78Gr+OX!eMh(yAz1J|<qG4_S5#8$}d;C$3?-p%h
-zoA>xOX?ins1JT%`W^G?fhur4fKIRUE*3QLETHZ|vFH46HExP_?I@he6ikgs;<9iE-
-zyb(P~-25+EUe@P|mrequ2#->vXNiV~g=3+)eL<<F*Oxs$mS_Gg+w1#9+vm$}Z-(BD
-z6D}q5T7IZAh2{>VUmD&Pj-&?Ft0n60mJaVM>_4C!b5M>%ONY0`>Q^o8U!k%8nx9Ie
-zAUw?Nk}d7C&266^vwdvgSkQ>{v^f3pxIM|@bf(3r^y4R!P>yd=_L*&{AdAyE=60#(
-zC!gJpB{d?verR9LS3g&cyzm|A{@__lH^O_->^5m{Pz}<jP1|>Ja{8x+=hWWo>4&0?
-ztaDFZD4o^vo71`8yVs9k^l)6;f59;9j@e_H=CuJ$-*4JJZ*@cK_W1Uzdk0#kMc@Bc
-ziEwYw@mpG0`n1Q*<`ijRfAD~|Uky6)>ycoZb<`s2jyopH(f0i%yBu3=nvcc3QKavH
-z?)8G**PI;ko*cOsW}bW+n?G-JmwXoA);063rhT;LXD+F}<wt+=i}GRJ>tD12?msSG
-zvctRimvuiO^<i*cr`~u6z6m&ydC?}RRMX$V?$ytbfBv)&jTVs4yT75f_x>d0NT{{8
-zwzj&uTHyZDH}t!NNcX}jU)^~7IJjtTZf<mRG$^Xx?`B;<IGMp%2#lb-de@n|(>_?j
-zTB8W(vo4^`n{;HfcR;~%7DrB~NWoQ=Oc448IJEVi)Q^|w(YNW-UkARHob@pKcW$cx
-z(?HxG<FCP;1@PS<5S(%Pgw^?I@Z#X3&}PHUk0$pfF?{b^`uAqe3nxB}Ze7V#-CbBX
-zwjw8@el$E{^cM{(xhif5M*oCDg8$e+(6SK9%xpk$Vxk(uRkq~UiW2+1UgTVMtu#n_
-zaQ=M<`{S=Hm#tDNi?~(T?07b66#7~SZ=21KHsO0JfpjF|E5>j{oMT~MOSvI_aLXna
-z2aef0u|C%s(f0613?t<fb7E~yH__KaVFRkjYh0{bLS`e9k6F#Y(>X;31@jys|K}(9
-zDIjN1x$<)Xqk6j1l24rtP~O&scOF_Bs1mXzZ29b$q-doe)x%O99dlo{etg$RZ8B2E
-z<oET{si(sd)T79tTib8kjxD$-k`t{I#f)tf<|qh;2jh#|+dqFUl^q%U&6*G<cg1ab
-zU=n+{B{!mZzBg;o^_7R4n_KvLcgJ?tHu;UY3-{cURkP&6>uw9!-W*-&XVc(McvtV6
-z&!upOo5gL*a7XaSARlf?Ns#FgwjXt9ie1!jN-q&-s*a&M7WJ=6FQ-WTrKbwYjyiB-
-z8>D4}KX*<jfxZXVl0Sw^hl%y;PED00T>d%xL8b`_+1(Kc;{>{bNAY=Og{d<Jo9={U
-zRDzVn3I;fQCK^HD^N}|a6Xls?y<oz5TNO=9Q1r2{*dv7H6?i3+4uL+U{4sKZ>BScm
-zjIe_CA0Y4zV8?CSOl5UG(bJ~jbdh(Z$T?GU6wTCZLB0PW_2iNXeg@)0G2Ww0;KQ^u
-zH$ha42nP(MJ5mimnc3L_Qs<$}-}ElM<P25vvv`t=4t6xd54$U^G5da;qjT{6+QELq
-zBk4h()hjjpB_lm?>-YNbsFd8GJDm02&=^$x3b}jBv4kS7yaLz!CfJqIng^Wa_~Jd-
-zVwSF(9~fy%sK;4=I0?piG6F1KUi8e6mWVXvZ-LSLyZz&gKr#2l%2OabU`dd}4Nho^
-zjWKm3<WcT6ij*rRw}<!=7QK-Nqsc_tLw2b>0=y{!WZvo3dmC#6*D_IT&td?f0~tWL
-zLp(`25o&2-_G^NCiro$;fP&|@g=6G^Knh8Pa#&iUsU7aMLfOT&gwk;7yfOg#)#=mb
-zIR(BdL3pQ%1xj+phm;T$60Yc{AqcO_rXEj%l*84oiM+sCA!fE@E{NHk#ZGurjZ|a#
-zqTTsSn=)kVY>JeeY|=0fV1fHzB6^|nu~L`yQn}EpnlqJOj(pb{1{<nd!JW9A`KtGN
-z3fx&`1>Qgy>;Vxx`gBOt(f|}d${`OXqA))c2$P%RpkBsM*iVv1xS)5xk{Q4p6L{mn
-zT4l()b8qVB<DmWh{py!(&})CSH9H`)xc#d`)D>+Ey;X*P29WVeNH!DTQRc~(S2oq{
-zP$=C*$EnTY69F_>>j`mz7>XiTT4*!zuiNJmN@9V=GV*@$!>~Pxkl8A<SWkTAZw5kP
-zJMSAjrW59L<vW-1DzTMqBc6(1{g!y)!VU$e#JI_Xv8@vWXe)Kib>COWg|*E&$lujg
-ztYd;IUs08P0%&Ih$uJfeLn2u1&`%kBRf<#!v<DrSj^tkw`J6cTx^sM~JmdO+5ZCMJ
-zjQK$%%8kQi&E?1lLfq){;Ddt8HoL*KOE{J34A?^mxAZB{2o6=`m%a;_*Y|KbDBov-
-zraEy&lS85c8kn|8ps09o!2%w}_lyB?Cf^z{w^c;zJm@YK9BxhNMH*q2TV+T!uwb>j
-zpkR7z02IO~ksIFnx>%68oB@*+#)Arn)<9KPw-Vmi-~M<3qo@@4I7lQXji-RV5gm%C
-z!p&c2rdrREoS#IT*kHAeNX_Dd3emd^a~v6SEh#G+YGJL~IS2l^-Z{9h&d;^CfkVvM
-zfJ$?jzGiXDt!Jybr90fY)B`S?KIAFQa$xRkn7kf)x;18U2pW1<h9;F&veY_pE|;dv
-zhf1k%|Ato+9lH92zvHh8e(lrE$!%lh5^$cJb|{3WN~x{sVzGxxf++E9_mD`8O+U-v
-z>UG5ps8qT%o6HX_Uj6<1RTP@S9D7cP=wJ7JxeQnElC(#bl2%5apt0i4nts+zpQjML
-zZ?><O5k$_=kH^hx@Zz++4m@is;jiONUH7)T+=OmZtsLXrLkcObn=xQv9ptZ;l&VPh
-ztCAnJ%B+zIHmik!8PfTL^_U>707-udHji|XKscuTr#Ev9p6Vigws;=QSm{}M6!&dV
-zPuvZWN%wusoWr@|k8miB_yReY7f7&F$|D{DN%xv6Id#3UwaEvRV(Ch$=97Y*K{L|L
-z3QQ$=TC091x)TrDaC<P?O}Msdnt|Ag)?3GCnwOID^OIms;ArbLJukvV!!ro4Kfaz~
-z-q5h-TGgI&VT*|E5#spK#-p9ua9QwQbLpN1>6c={EoF3NUN_A^o?Z$C%2;R;@=v^J
-zDmwda^wf>;qk?_hJA}&}>*TdT?EL_+kR2<XUc)+;ZAD+Hms2PSogQCy;UG{Q-f$$!
-z;&z1`(Q{)5(;QX;9dFqE(!<M@`e#E<&y<^`$;6fl^-tv$MH1_~4p?$Sm~7BZffkKh
-z>Q;-{aDeNXGQX|F&Y54y^pYSA2q2{o)n?6e{5fa?m|i@vNk7Qr3Am?S;K*DL0_)Qq
-z6$gg{@uFwT0R#^a{xo>j8CCV6n{IIE)Sm5c-k6}lC^A|2ApIOro3mYHf0OVSi>_*-
-z+kxa4FFgzy{XHW8EvbqO)FX3=V0{Al%PkMT5<;<>;8#kEu!|O8<=lDb$2B(%i;YU;
-zfpxnEC8!}1>{B=L5``sSB)p@=*!iEp0_J2ilpbK^mjj~j1%jVcA*Fx8@js+?di9g2
-zORTRo$k$%dvZ>7Zxos_6%k45d$9h|TAFe~5WhXT5D6|)YJxy2VhpL(sn7&e)^?@py
-z<gvFr0Rq_B!Bzzoa@pb2Eg|{LzrOlTTM~A@O}xV|t**X<g4Bi5)C8A_B;>SW48X0J
-zk?-`x@sD+O6RNjELB`BZNhbB(GJM$~txEts2`JnjM#xSHIm|oEEFFJ+*m$h?qvS1*
-zqk$*3@k>!<M1JF$e57<eq|W!x0-&TKkfn(PPfcs=Z>iyO4eQcy%3F^%o@q2ysaEy>
-zGhE-J^noyXA#x<tJYwKod;x8Z;-_>3OFMJ&BGK1XeCw^E;OrCqJ6&7{DA(e-A%^`(
-z{NuTHmL;gS;v3Vh4f_JF5c4Hg5YfAl8y*yXTiEXfy4bA@90w$dvWf0v;w&cCg!WqZ
-zcFkC1jp;rl-bj6AqAY;LHznAOOn70MHg^t*E_(^fyCAdZ9il(b-6v)1n5~c%QkiE7
-zh5rK9^jraGCTU$aCnymORHnsRA(YSkAsHLv*w*-ILAj`z6JWARRAuRIi8j8$VenJV
-zeH8W%8(cOVCmPZQoX0AsGlc1Z`0~He_0f1C*bTXZHpF)MBa8?=sAR!$X%^cpft`^{
-zjCBTY9~*Fs7T`Km=WvFY$w?PS*}A{f=MDV8wHMgShAp0WLVaUOb=jKW;RM`_FDK+h
-za`PEPFNzt^|MuTT(xi%beF^S+pQ*dqiD#CQtb&iQC<9~!73!OMTn30JP*_FeK{0Fk
-z(HeD1w+S+dRmoW^kHSR_avxwxZ-`w7r%6>6;;|NJ<UY}hm{&+(R}5YqqI3%12(Gap
-zjtnCG#*qmG>0BUY3TFuVIBn-%uRC+@oiNWP%z9%1t`J>MS}tVSH8K;yH)YReD~Nbd
-zg~3@nOYR^xYpqqw%<2Mu71T|7J8Acb)v86nqAfT(L^EIyY{J&H79I!whWN6fJFWnI
-zn=t3n&F8rI3;rsLJ~6Nwgz=4hUGAjr94SG!U=x$HmC2(?5c`e-)v>$ZOUhM<sVA8$
-z0^D3`7y0&r+a0T6ai9?FVZe=`@aGHGaPE@Swn>_gFxcp40sG4(wPq-Nzp^@nWWw*2
-zd`aUJV_Qhcv(z5$ymugFIgKnLz&*;-Jc~O?xpuHY?4xz+Y#QElQ^Q0UsKV#LWCC&7
-z480|ZI4D{mNy6uB2rd-EQ5q$&64x*70iKayA5>5LQHeM*PS&OZyw8gyEK3*uSnk~b
-zz;G2OYmh34gY8f~!Id-_rvn@ToiH;^a^%lj4I?GxZ8771-B@^utVkkO2BL+=43e(s
-zA-E@ZbT!wU`43TkiBxe8J&CiRd42n5As%^qGqLCf`rrjYd0sE*`+(cMZW0tG(}I2U
-zmpWTO)X@m*>92|vToa@Rq7Po$F!~8ft-MNqfQ2rRLb}NFZmtMp)g0w$lqyQGg&gS3
-zu*(@}vn0xlV6#}b7^5-pL7)4a7wc3LN!0$tU##4^St^E|p9;ie#;8?r>DALNcKm%W
-z0Jl#(Dy;nEYjF!}K6#2-8PbOhI3Q{Q|GVYN%~*z+xYC*zc&CYYBqy(3gD8bW`}JWz
-z`{Aiz+P$Hqw=#X$OL;`47qIdh6;oXEs7NE?2clA&=!rxTS%Tw6*zxk6fSB{^*g#O{
-zN*}Q6)PMHve&Tc)r=pGi=dsoMh2?JR*dWkSUu++c2Dr(K`(ZP$u+VwZQX4jLlDG;w
-zzUM#S{&eD@1UwJQdxh=8W=&CtnOHpK=^v^_Gs%&+Pe4UrhV~L=+Wt#tumLRuf19CV
-zR^`aSx7!`m4B?)G&w&Pmn)U6ls}q57#k|rU5mEVt%;;MJ8a-huT8X?)R%No|q2p&%
-zG}qGA#8FY@;#NmK-XoI-`ukksinY%LsQ#Wef~<fEa1fOHrPy71Xm>@xm^QJ#{JZ0Z
-z=F=&&Ri%^Db!+2xnM>Caojxf{G$wk)C2YpR3oweo2k29ifZgV8L4PjQi+?n6;@O0;
-z`eScnAsaIXe<VN=z}izz)bB2+Nem}u7hyFJ#DGbZt+0;4H!?GidLlz8YoiXCSSSXa
-zMW2I?ocV0~Tzn6szpL!#aauGAG`k}m8;wTv)S^t19*@bKU_4eTiI$q((T{aPdkgRG
-z_kq&1UKNZA>u62jHeEd;6EMoTSL=R}mbR@X{(`JV{-fMG=xj6V4T()^w@gIY(A|i3
-zhp*ZF9c;7IC+9Y)1+l4hEAFsSuoHSx7>pUJEE_5|9a2s|eNCZ8y(KR(@{G@bb!};l
-zNz`g|162;I^IhZ}ez(@cDdHI%QRZv9(Wi5`;Ogb8h24ba=10z1A5OFUd?I%o+BqF(
-z|4+cff))UrJX|k*{K(+N078XMUk=hh?_qGn_BV1*LO<w*p}+pC`uKcuktm=)^(oC0
-zmx!-TR?FUIyX}Ekxt)yELqUs@u*h}ajjUVEY>RHmoJK)yv$IV9+5i0Be}7%4ZO@)4
-Ivi6GmKTIFPX#fBK
-
-diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
-index b960a27..975087e 100644
---- a/app/src/main/res/values/styles.xml
-+++ b/app/src/main/res/values/styles.xml
-@@ -1,4 +1,3 @@
- <resources>
--
-     <style name="AppTheme" parent="@android:style/Theme.NoDisplay"/>
- </resources>
-diff --git a/gradlew b/gradlew
-old mode 100755
-new mode 100644
-diff --git a/gradlew.bat b/gradlew.bat
-index aec9973..8a0b282 100644
---- a/gradlew.bat
-+++ b/gradlew.bat
-@@ -1,90 +1,90 @@
--@if "%DEBUG%" == "" @echo off\r
--@rem ##########################################################################\r
--@rem\r
--@rem  Gradle startup script for Windows\r
--@rem\r
--@rem ##########################################################################\r
--\r
--@rem Set local scope for the variables with windows NT shell\r
--if "%OS%"=="Windows_NT" setlocal\r
--\r
--@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
--set DEFAULT_JVM_OPTS=\r
--\r
--set DIRNAME=%~dp0\r
--if "%DIRNAME%" == "" set DIRNAME=.\r
--set APP_BASE_NAME=%~n0\r
--set APP_HOME=%DIRNAME%\r
--\r
--@rem Find java.exe\r
--if defined JAVA_HOME goto findJavaFromJavaHome\r
--\r
--set JAVA_EXE=java.exe\r
--%JAVA_EXE% -version >NUL 2>&1\r
--if "%ERRORLEVEL%" == "0" goto init\r
--\r
--echo.\r
--echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
--echo.\r
--echo Please set the JAVA_HOME variable in your environment to match the\r
--echo location of your Java installation.\r
--\r
--goto fail\r
--\r
--:findJavaFromJavaHome\r
--set JAVA_HOME=%JAVA_HOME:"=%\r
--set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
--\r
--if exist "%JAVA_EXE%" goto init\r
--\r
--echo.\r
--echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
--echo.\r
--echo Please set the JAVA_HOME variable in your environment to match the\r
--echo location of your Java installation.\r
--\r
--goto fail\r
--\r
--:init\r
--@rem Get command-line arguments, handling Windowz variants\r
--\r
--if not "%OS%" == "Windows_NT" goto win9xME_args\r
--if "%@eval[2+2]" == "4" goto 4NT_args\r
--\r
--:win9xME_args\r
--@rem Slurp the command line arguments.\r
--set CMD_LINE_ARGS=\r
--set _SKIP=2\r
--\r
--:win9xME_args_slurp\r
--if "x%~1" == "x" goto execute\r
--\r
--set CMD_LINE_ARGS=%*\r
--goto execute\r
--\r
--:4NT_args\r
--@rem Get arguments from the 4NT Shell from JP Software\r
--set CMD_LINE_ARGS=%$\r
--\r
--:execute\r
--@rem Setup the command line\r
--\r
--set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
--\r
--@rem Execute Gradle\r
--"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
--\r
--:end\r
--@rem End local scope for the variables with windows NT shell\r
--if "%ERRORLEVEL%"=="0" goto mainEnd\r
--\r
--:fail\r
--rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
--rem the _cmd.exe /c_ return code!\r
--if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
--exit /b 1\r
--\r
--:mainEnd\r
--if "%OS%"=="Windows_NT" endlocal\r
--\r
--:omega\r
-+@if "%DEBUG%" == "" @echo off
-+@rem ##########################################################################
-+@rem
-+@rem  Gradle startup script for Windows
-+@rem
-+@rem ##########################################################################
-+
-+@rem Set local scope for the variables with windows NT shell
-+if "%OS%"=="Windows_NT" setlocal
-+
-+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-+set DEFAULT_JVM_OPTS=
-+
-+set DIRNAME=%~dp0
-+if "%DIRNAME%" == "" set DIRNAME=.
-+set APP_BASE_NAME=%~n0
-+set APP_HOME=%DIRNAME%
-+
-+@rem Find java.exe
-+if defined JAVA_HOME goto findJavaFromJavaHome
-+
-+set JAVA_EXE=java.exe
-+%JAVA_EXE% -version >NUL 2>&1
-+if "%ERRORLEVEL%" == "0" goto init
-+
-+echo.
-+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-+echo.
-+echo Please set the JAVA_HOME variable in your environment to match the
-+echo location of your Java installation.
-+
-+goto fail
-+
-+:findJavaFromJavaHome
-+set JAVA_HOME=%JAVA_HOME:"=%
-+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-+
-+if exist "%JAVA_EXE%" goto init
-+
-+echo.
-+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-+echo.
-+echo Please set the JAVA_HOME variable in your environment to match the
-+echo location of your Java installation.
-+
-+goto fail
-+
-+:init
-+@rem Get command-line arguments, handling Windowz variants
-+
-+if not "%OS%" == "Windows_NT" goto win9xME_args
-+if "%@eval[2+2]" == "4" goto 4NT_args
-+
-+:win9xME_args
-+@rem Slurp the command line arguments.
-+set CMD_LINE_ARGS=
-+set _SKIP=2
-+
-+:win9xME_args_slurp
-+if "x%~1" == "x" goto execute
-+
-+set CMD_LINE_ARGS=%*
-+goto execute
-+
-+:4NT_args
-+@rem Get arguments from the 4NT Shell from JP Software
-+set CMD_LINE_ARGS=%$
-+
-+:execute
-+@rem Setup the command line
-+
-+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-+
-+@rem Execute Gradle
-+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-+
-+:end
-+@rem End local scope for the variables with windows NT shell
-+if "%ERRORLEVEL%"=="0" goto mainEnd
-+
-+:fail
-+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-+rem the _cmd.exe /c_ return code!
-+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-+exit /b 1
-+
-+:mainEnd
-+if "%OS%"=="Windows_NT" endlocal
-+
-+:omega
--- 
-2.11.1
-