Android Open Source - detectivemode Core






From Project

Back to project page detectivemode.

License

The source code is released under:

GNU General Public License

If you think the Android project detectivemode listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.dotslashzero.detectivemode;
//from  www  . ja va 2  s .co m
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;

public final class Core implements IXposedHookLoadPackage
{
    public static final String LOG_TAG = new String("Detective Mode");

    private static class Config
    {
        private Config()
        {
        }

        private static boolean getBooleanValue(String key)
        {
            try {
                XSharedPreferences prefs = new XSharedPreferences(Core.class.getPackage().getName(), "settings");
                return (prefs.getBoolean(key, false));
            }
            catch (Exception e) {
                Log.e(LOG_TAG, "An error has occurred while reading preferences.");
                return (false);
            }
        }

        public static boolean isBrowserIncognito()
        {
            return (Config.getBooleanValue("com.android.browser"));
        }

        public static boolean isChromeIncognito()
        {
            return (Config.getBooleanValue("com.android.chrome"));
        }

        public static boolean isFirefoxIncognito()
        {
            return (Config.getBooleanValue("org.mozilla.firefox"));
        }
    }

    public Core()
    {
        super();
    }

    @Override
    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable
    {
        if (lpparam.packageName.equals("com.android.browser"))
            this.applyIncognitoModBrowser(lpparam);

        if (lpparam.packageName.equals("com.android.chrome"))
            this.applyIncognitoModChrome(lpparam);

        if (lpparam.packageName.equals("org.mozilla.firefox"))
            this.applyIncognitoModFirefox(lpparam);

        return;
    }

    private void applyIncognitoModBrowser(LoadPackageParam lpparam) throws Throwable
    {
        // Hook into com.android.browser.BrowserActivity.onDestroy and
        // com.android.browser.BrowserActivity.onPause

        final Class<?> comAndroidBrowserBrowserActivityClass = XposedHelpers.findClass(
            "com.android.browser.BrowserActivity", lpparam.classLoader);

        // To clear the browsing data in com.android.browser, invoke the
        // following
        // method:
        // import com.android.browser.BrowserSettings;
        // BrowserSettings settings = BrowserSettings.getInstance();
        // settings.clearCache();
        // settings.clearCookies();
        // settings.clearDatabases();
        // settings.clearFormData();
        // settings.clearHistory();
        // settings.clearLocationAccess();
        // settings.clearPasswords();

        final Class<?> comAndroidBrowserBrowserSettings = XposedHelpers.findClass(
            "com.android.browser.BrowserSettings", lpparam.classLoader);

        final XC_MethodHook clearBrowsingDataHook = new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable
            {
                if (!Config.isBrowserIncognito())
                    return;

                Log.i(Core.LOG_TAG, "Called method: \"" + param.method.getName() + "\"");

                Log.i(Core.LOG_TAG, "Clearing browsing data...");

                Object browserSettingsInstance = XposedHelpers.callStaticMethod(comAndroidBrowserBrowserSettings,
                    "getInstance");

                XposedHelpers.callMethod(browserSettingsInstance, "clearCache");
                XposedHelpers.callMethod(browserSettingsInstance, "clearCookies");
                XposedHelpers.callMethod(browserSettingsInstance, "clearDatabases");
                XposedHelpers.callMethod(browserSettingsInstance, "clearFormData");
                XposedHelpers.callMethod(browserSettingsInstance, "clearHistory");
                XposedHelpers.callMethod(browserSettingsInstance, "clearLocationAccess");
                XposedHelpers.callMethod(browserSettingsInstance, "clearPasswords");

                return;
            }
        };

        // The onPause handler is called when the app goes out of focus (i.e.
        // fast
        // switching).
        XposedHelpers.findAndHookMethod(comAndroidBrowserBrowserActivityClass, "onPause", clearBrowsingDataHook);

        // The onDestroy handler is called when the app closes because there are
        // no
        // more tabs to display.
        XposedHelpers.findAndHookMethod(comAndroidBrowserBrowserActivityClass, "onDestroy", clearBrowsingDataHook);

        return;
    }

    private void applyIncognitoModChrome(LoadPackageParam lpparam) throws Throwable
    {
        // Solution 1 was to always open incognito tabs, but this, however,
        // causes Chrome
        // to crash unexpectedly from time to time.

        /*
        final Class<?> orgChromiumChromeBrowserTabClass =
            XposedHelpers.findClass("org.chromium.chrome.browser.Tab", lpparam.classLoader);

        final Class<?> androidContentContextClass =
            XposedHelpers.findClass("android.content.Context", lpparam.classLoader);

        final Class<?> orgChromiumUiBaseWindowAndroidClass = 
            XposedHelpers.findClass("org.chromium.ui.base.WindowAndroid", lpparam.classLoader);
        
        final Class<?> intType = XposedHelpers.findClass("int", lpparam.classLoader);
        final Class<?> booleanType = XposedHelpers.findClass("boolean", lpparam.classLoader);
        
        XposedHelpers.findAndHookConstructor(
            orgChromiumChromeBrowserTabClass,
            intType,
            intType,
            booleanType,
            androidContentContextClass,
            orgChromiumUiBaseWindowAndroidClass,
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable
                {
                    Object[] args = param.args;
                    for (int i = 0; i < args.length; i++) {
                        if (args[i] instanceof Boolean) {
                            args[i] = true;
                        }
                    }
                    return;
                }
            }
        );
        */

        // Solution 2 is to clear browsing history (silently in the background)
        // when the app
        // goes to background, or session ends.

        final Class<?> comGoogleAndroidAppsChromePreferencesChromeNativePreferencesClass = XposedHelpers.findClass(
            "com.google.android.apps.chrome.preferences.ChromeNativePreferences", lpparam.classLoader);

        final Class<?> comGoogleAndroidAppsChromePreferencesChromeNativePreferencesChromeNativePreferencesOnClearBrowsingDataListenerClass = XposedHelpers
            .findClass(
                "com.google.android.apps.chrome.preferences.ChromeNativePreferences.OnClearBrowsingDataListener",
                lpparam.classLoader);

        final Class<?> booleanType = XposedHelpers.findClass("boolean", lpparam.classLoader);

        // This function clears the browsing history:
        // import
        // com.google.android.apps.chrome.preferences.ChromeNativePreferences;
        // ChromeNativePreferences.getInstance().clearBrowsingData(null, true,
        // true, true, true, true)

        final XC_MethodHook clearBrowsingDataHook = new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable
            {
                if (!Config.isChromeIncognito())
                    return;

                Log.i(Core.LOG_TAG, "Called method: \"" + param.method.getName() + "\"");

                Log.i(Core.LOG_TAG, "Clearing browsing data...");

                Object chromeNativePreferencesInstance = XposedHelpers.callStaticMethod(
                    comGoogleAndroidAppsChromePreferencesChromeNativePreferencesClass, "getInstance");

                Class<?>[] parameterTypes = new Class<?>[6];
                parameterTypes[0] = comGoogleAndroidAppsChromePreferencesChromeNativePreferencesChromeNativePreferencesOnClearBrowsingDataListenerClass;
                parameterTypes[1] = booleanType;
                parameterTypes[2] = booleanType;
                parameterTypes[3] = booleanType;
                parameterTypes[4] = booleanType;
                parameterTypes[5] = booleanType;

                XposedHelpers.callMethod(chromeNativePreferencesInstance, "clearBrowsingData", parameterTypes, null,
                    true, true, true, true, true);

                return;
            }
        };

        final Class<?> comGoogleAndroidAppsChromeChromeMobileApplicationClass = XposedHelpers.findClass(
            "com.google.android.apps.chrome.ChromeMobileApplication", lpparam.classLoader);

        // It seems that this is called on a different situation.
        /*
        XposedHelpers.findAndHookMethod(
            comGoogleAndroidAppsChromeChromeMobileApplicationClass,
            "onForegroundActivityDestroyed",
            clearBrowsingDataHook
        );
        */

        XposedHelpers.findAndHookMethod(comGoogleAndroidAppsChromeChromeMobileApplicationClass,
            "onForegroundSessionEnd", clearBrowsingDataHook);

        /*
        // This is just a hook to log the call to "clearBrowsingData". It is only for debugging
        // purposes.
        XposedHelpers.findAndHookMethod(
            comGoogleAndroidAppsChromePreferencesChromeNativePreferencesClass,
            "clearBrowsingData",
            comGoogleAndroidAppsChromePreferencesChromeNativePreferencesChromeNativePreferencesOnClearBrowsingDataListenerClass,
            booleanType,
            booleanType,
            booleanType,
            booleanType,
            booleanType,
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable
                {
                    int count = 1;
                    StringBuilder sb = new StringBuilder();
                    sb.append("clearBrowsingData method called with:");
                    sb.append(System.lineSeparator());
                    for (Object arg : param.args) {
                        if (arg instanceof Boolean) {
                            Boolean boolArg = (Boolean) arg;
                            sb.append("\tboolean");
                            sb.append(count);
                            sb.append(": ");
                            sb.append(boolArg.booleanValue() ? "true" : "false");
                            sb.append(System.lineSeparator());
                            count++;
                        }
                    }
                    Log.i(Core.LOG_TAG, sb.toString());
                    return;
                }
            }
        );
        */

        return;
    }

    private void applyIncognitoModFirefox(LoadPackageParam lpparam) throws Throwable
    {
        final Class<?> orgMozillaGeckoBrowserAppClass = XposedHelpers.findClass("org.mozilla.gecko.BrowserApp",
            lpparam.classLoader);
        final Class<?> orgMozillaGeckoGeckoAppShellClass = XposedHelpers.findClass("org.mozilla.gecko.GeckoAppShell",
            lpparam.classLoader);
        final Class<?> orgMozillaGeckoGeckoEventClass = XposedHelpers.findClass("org.mozilla.gecko.GeckoEvent",
            lpparam.classLoader);
        final Class<?> javaLangStringClass = XposedHelpers.findClass("java.lang.String", lpparam.classLoader);

        final XC_MethodHook clearBrowsingDataHook = new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable
            {
                if (!Config.isFirefoxIncognito())
                    return;

                Log.i(Core.LOG_TAG, "Called method: \"" + param.method.getName() + "\"");

                Log.i(Core.LOG_TAG, "Clearing browsing data...");

                // 1. invoke:
                // GeckoEvent event =
                // GeckoEvent.createBroadcastEvent("Sanitize:ClearData",
                // jsonArg)
                // where:
                // jsonArg =
                // {
                // "history":true,
                // "formdata":true,
                // "passwords":true,
                // "cache":true,
                // "offlineApps":true,
                // "downloadFiles":true,
                // "siteSettings":true,
                // "cookies_sessions":true
                // }
                Class<?>[] parameterTypes = new Class<?>[2];
                parameterTypes[0] = javaLangStringClass;
                parameterTypes[1] = javaLangStringClass;
                final String jsonArg = "{" + "\"history\":true," + "\"formdata\":true," + "\"passwords\":true,"
                    + "\"cache\":true," + "\"offlineApps\":true," + "\"downloadFiles\":true,"
                    + "\"siteSettings\":true," + "\"cookies_sessions\":true" + "}";
                Object clearDataEvent = XposedHelpers.callStaticMethod(orgMozillaGeckoGeckoEventClass,
                    "createBroadcastEvent", parameterTypes, "Sanitize:ClearData", jsonArg);

                // 2. invoke:
                // GeckoAppShell.sendEventToGecko(event)
                parameterTypes = new Class<?>[1];
                parameterTypes[0] = orgMozillaGeckoGeckoEventClass;
                XposedHelpers.callStaticMethod(orgMozillaGeckoGeckoAppShellClass, "sendEventToGecko", parameterTypes,
                    clearDataEvent);

                return;
            }
        };

        XposedHelpers.findAndHookMethod(orgMozillaGeckoBrowserAppClass, "onPause", clearBrowsingDataHook);

        XposedHelpers.findAndHookMethod(orgMozillaGeckoBrowserAppClass, "onDestroy", clearBrowsingDataHook);

        // Test only
        /*
        XposedHelpers.findAndHookMethod(
            orgMozillaGeckoGeckoEventClass,
            "createBroadcastEvent",
            javaLangStringClass,
            javaLangStringClass,
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable
                {
                    Object[] args = param.args;
                    if (args.length > 0) {
                        if (args[0] instanceof String) {
                            if (((String) args[0]).equals("Sanitize:ClearData")) {
                                Log.i(Core.LOG_TAG, "Called method: \"" + param.method.getName() + "\"");
                                Log.i(Core.LOG_TAG, "With arguments: " + ((String) args[1]));
                            }
                        }
                    }
                    
                    return;
                }
            }
        );
        */

        return;
    }
}




Java Source Code List

net.dotslashzero.detectivemode.ConfigCheck.java
net.dotslashzero.detectivemode.Core.java
net.dotslashzero.detectivemode.MainActivity.java
net.dotslashzero.detectivemode.dialog.AboutDialogFragment.java