Back to project page detectivemode.
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.
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; } }