@Override public void initZygote(StartupParam startupParam) throws Throwable { sModulePath = startupParam.modulePath; sPrefs = new XSharedPreferences(PACKAGE_OWN); RomUtils.init(sPrefs); logI(TAG, "Version " + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")"); //noinspection ConstantConditions if (BuildConst.BUILD_SERVER_VERSION == 0) { logI( TAG, "Official Build; Release: " + !BuildConfig.DEBUG + " (" + BuildConfig.BUILD_TYPE + ")"); } else { logI(TAG, "Remote Build; Version: " + BuildConst.BUILD_SERVER_VERSION); } logI(TAG, "ROM type: " + sPrefs.getString("rom", "undefined")); if (!sPrefs.getBoolean("can_read_prefs", false)) { // With SELinux enforcing, it might happen that we don't have access // to the prefs file. Test this by reading a test key that should be // set to true. If it is false, we either can't read the file or the // user has never opened the preference screen before. logW(TAG, "Can't read prefs file, default values will be applied in hooks!"); } }
public static void modCode(LoadPackageParam lparam) { PaperLogger.log("KyoboLibrary"); if (pref.getBoolean(prefKey, false) == false) return; PaperLogger.log("KyoboLibrary module is active"); KyoboPlatform.modCode(lparam, packageName); }
@Override public void initZygote(StartupParam startupParam) throws Throwable { MODULE_PATH = startupParam.modulePath; prefs = new XSharedPreferences(PACKAGE_NAME); XposedBridge.log("Hardware: " + Build.HARDWARE); XposedBridge.log("Product: " + Build.PRODUCT); XposedBridge.log("Device manufacturer: " + Build.MANUFACTURER); XposedBridge.log("Device brand: " + Build.BRAND); XposedBridge.log("Device model: " + Build.MODEL); XposedBridge.log("Is MTK device: " + Utils.isMtkDevice()); XposedBridge.log("Android SDK: " + Build.VERSION.SDK_INT); XposedBridge.log("Android Release: " + Build.VERSION.RELEASE); XposedBridge.log("ROM: " + Build.DISPLAY); SystemWideResources.initResources(prefs); // MTK specific if (Utils.isMtkDevice()) { ModSignalIconHide.initZygote(prefs); if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_CALLER_ID_PHONE, false)) { FixCallerIdPhone.initZygote(prefs); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_DEV_OPTS, false)) { FixDevOptions.initZygote(); } } // Common FixTraceFlood.initZygote(); ModVolumeKeySkipTrack.init(prefs); ModVolKeyCursor.initZygote(prefs); ModCallCard.initZygote(); ModStatusbarColor.initZygote(); PhoneWrapper.initZygote(); ModElectronBeam.initZygote(prefs); ModLockscreen.initZygote(prefs); ModLowBatteryWarning.initZygote(prefs); ModDisplay.initZygote(prefs); ModAudio.initZygote(prefs); ModHwKeys.initZygote(prefs); PatchMasterKey.initZygote(); }
public static void doHook(XSharedPreferences prefs, ClassLoader classLoader) { XSysUiSmartAlarmPackage.prefs = prefs; XSysUiSmartAlarmPackage.classLoader = classLoader; if (prefs.getBoolean("hideAlarmClockIcon", false)) { hideAlarmIcon(); } }
@Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { switch (lpparam.packageName) { case PACKAGE_SETTINGS: SettingsHooks.hook(lpparam.classLoader); break; case PACKAGE_SYSTEMUI: SystemUIHooks.hookSystemUI(lpparam.classLoader); StatusBarHeaderHooks.hook(lpparam.classLoader); NotificationPanelHooks.hook(lpparam.classLoader); StackScrollAlgorithmHooks.hook(lpparam.classLoader); NotificationHooks.hookSystemUI(lpparam.classLoader); RecentsStackHooks.hookSystemUI(lpparam.classLoader); RecentsNavigation.hookSystemUI(lpparam.classLoader); DoubleTapSwKeys.hook(lpparam.classLoader); break; case PACKAGE_ANDROID: DoubleTapHwKeys.hook(lpparam.classLoader); LiveDisplayObserver.hook(lpparam.classLoader); PermissionGranter.initAndroid(lpparam.classLoader); break; case PACKAGE_PHONE: EmergencyHooks.hook(lpparam.classLoader); break; case PACKAGE_OWN: XposedHelpers.findAndHookMethod( SETTINGS_OWN, lpparam.classLoader, "isActivated", XC_MethodReplacement.returnConstant(true)); if (!sPrefs.getBoolean("can_read_prefs", false)) XposedHelpers.findAndHookMethod( SETTINGS_OWN, lpparam.classLoader, "isPrefsFileReadable", XC_MethodReplacement.returnConstant(false)); break; } // Has to be hooked in every app as every app creates own instances of the Notification.Builder NotificationHooks.hook(lpparam.classLoader); // This actually is only used in the system process, but every app has access, so just to be // sure hook everything if (ConfigUtils.qs().enable_qs_editor) { try { Class<?> classCMStatusBarManager = XposedHelpers.findClass("cyanogenmod.app.CMStatusBarManager", lpparam.classLoader); XposedBridge.hookAllMethods( classCMStatusBarManager, "publishTile", XC_MethodReplacement.DO_NOTHING); XposedBridge.hookAllMethods( classCMStatusBarManager, "publishTileAsUser", XC_MethodReplacement.DO_NOTHING); } catch (Throwable ignore) { } } }
public static void setTypeFace(View v) { XSharedPreferences pref = new XSharedPreferences("hello.dcsms.omzen"); pref.makeWorldReadable(); boolean usecustomfont = pref.getBoolean("CUSTOM_FONT", false); if (usecustomfont) { Typeface tf = Typeface.createFromFile( Environment.getExternalStorageDirectory().getAbsolutePath() + "/default_icon" + "/font_satu.ttf"); ((TextView) v).setTypeface(tf); } }
@Override public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { // MTK Specific if (Utils.isMtkDevice()) { if (lpparam.packageName.equals(ModSignalIconHide.PACKAGE_NAME)) { ModSignalIconHide.init(prefs, lpparam.classLoader); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_CALLER_ID_MMS, false) && lpparam.packageName.equals(FixCallerIdMms.PACKAGE_NAME)) { FixCallerIdMms.init(prefs, lpparam.classLoader); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_CALENDAR, false) && lpparam.packageName.equals(FixCalendar.PACKAGE_NAME)) { FixCalendar.init(prefs, lpparam.classLoader); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_DATETIME_CRASH, false) && lpparam.packageName.equals(FixDateTimeCrash.PACKAGE_NAME)) { FixDateTimeCrash.init(prefs, lpparam.classLoader); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_TTS_SETTINGS, false) && lpparam.packageName.equals(FixTtsSettings.PACKAGE_NAME)) { FixTtsSettings.init(prefs, lpparam.classLoader); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_DEV_OPTS, false) && lpparam.packageName.equals(FixDevOptions.PACKAGE_NAME)) { FixDevOptions.init(prefs, lpparam.classLoader); } if (prefs.getBoolean(GravityBoxSettings.PREF_KEY_FIX_MMS_WAKELOCK, false) && lpparam.packageName.equals(FixMmsWakelock.PACKAGE_NAME)) { FixMmsWakelock.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModAudioSettings.PACKAGE_NAME)) { ModAudioSettings.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModCellConnService.PACKAGE_NAME)) { ModCellConnService.init(prefs, lpparam.classLoader); } } // Common if (lpparam.packageName.equals(ModBatteryStyle.PACKAGE_NAME)) { ModBatteryStyle.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModLowBatteryWarning.PACKAGE_NAME)) { ModLowBatteryWarning.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModClearAllRecents.PACKAGE_NAME)) { ModClearAllRecents.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModRebootMenu.PACKAGE_NAME)) { ModRebootMenu.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModCallCard.PACKAGE_NAME)) { ModCallCard.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModQuickSettings.PACKAGE_NAME)) { ModQuickSettings.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModStatusbarColor.PACKAGE_NAME)) { ModStatusbarColor.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModCenterClock.PACKAGE_NAME)) { ModCenterClock.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModPhone.PACKAGE_NAME)) { ModPhone.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModSettings.PACKAGE_NAME)) { ModSettings.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModVolumePanel.PACKAGE_NAME)) { ModVolumePanel.init(prefs, lpparam.classLoader); } if (lpparam.packageName.equals(ModPieControls.PACKAGE_NAME)) { ModPieControls.init(prefs, lpparam.classLoader); } }
private void patchcode() { XSharedPreferences prefs = new XSharedPreferences(XpStatus.PKGNAME, XpStatus.PREF); prefs.makeWorldReadable(); prefs.reload(); if (!prefs.getBoolean(XpStatus.KEY_REMOVEAD, false)) { return; } if (loadPackageParam.packageName.equals("com.miui.core")) { XpUtils.findAndHookMethod( "miui.os.SystemProperties", loadPackageParam.classLoader, "get", String.class, String.class, new XC_MethodHook() { protected void afterHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { if (paramAnonymousMethodHookParam .args[0] .toString() .equals("ro.product.mod_device")) { paramAnonymousMethodHookParam.setResult("gemini_global"); } } protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { if (paramAnonymousMethodHookParam .args[0] .toString() .equals("ro.product.mod_device")) { paramAnonymousMethodHookParam.setResult("gemini_global"); } } }); return; } if (loadPackageParam.packageName.equals("com.miui.cleanmaster")) { XpUtils.findAndHookMethod( "com.miui.optimizecenter.result.DataModel", loadPackageParam.classLoader, "post", Map.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { paramAnonymousMethodHookParam.setResult(""); } }); XpUtils.findAndHookMethod( "com.miui.optimizecenter.config.MiStat", loadPackageParam.classLoader, "getChannel", new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { paramAnonymousMethodHookParam.setResult("international"); } }); return; } if (loadPackageParam.packageName.equals("com.miui.video")) { XpUtils.findAndHookMethod( "com.miui.videoplayer.ads.DynamicAd", loadPackageParam.classLoader, "replaceList", List.class, String.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { paramAnonymousMethodHookParam.args[0] = null; paramAnonymousMethodHookParam.args[1] = null; } }); XpUtils.findAndHookMethod( "com.video.ui.view.AdView", loadPackageParam.classLoader, "getAdsBlock", Context.class, XC_MethodReplacement.returnConstant(null)); Class<?> clsCallback = XpUtils.findClass( loadPackageParam.classLoader, "com.video.ui.idata.SyncServiceHelper$Callback"); if (clsCallback != null) { XpUtils.findAndHookMethod( "com.video.ui.idata.SyncServiceHelper", loadPackageParam.classLoader, "fetchAds", Context.class, clsCallback, XC_MethodReplacement.returnConstant(null)); } XpUtils.findAndHookMethod( "com.video.ui.idata.iDataORM", loadPackageParam.classLoader, "getBooleanValue", Context.class, String.class, boolean.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { String key = (String) param.args[1]; if (key.equals("debug_mode") || key.equals("show_first_ads") || key.equals("ads_show_homekey") || key.equals("startup_ads_loop") || key.equals("app_upgrade_splash")) { param.setResult(false); } } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { String key = (String) param.args[1]; if (key.equals("debug_mode") || key.equals("show_first_ads") || key.equals("ads_show_homekey") || key.equals("startup_ads_loop") || key.equals("app_upgrade_splash")) { param.setResult(false); } } }); XpUtils.findAndHookMethod( "com.video.ui.idata.iDataORM", loadPackageParam.classLoader, "getStringValue", Context.class, String.class, String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { String key = (String) param.args[1]; if (key.equals("startup_ads")) { param.setResult(null); } } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { String key = (String) param.args[1]; if (key.equals("startup_ads")) { param.setResult(null); } } }); return; } if (loadPackageParam.packageName.equals("com.android.fileexplorer")) { XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "isAdEnable", Context.class, String.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "supportAd", XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "ifAdShowByCloudForNetwork", Context.class, String.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "getHomePageHotVideoTipSwitch", Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "getHomePageHotVideoTopicUri", Context.class, XC_MethodReplacement.returnConstant("")); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "getAdStyleName", Context.class, String.class, XC_MethodReplacement.returnConstant("")); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "tryInit", Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "isVideoEnable", Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.model.ConfigHelper", loadPackageParam.classLoader, "isStickerEnable", Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.android.fileexplorer.util.XLUtil", loadPackageParam.classLoader, "isNetworkAvailable", Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.xunlei.adlibrary.XunleiADSdk", loadPackageParam.classLoader, "setup", Context.class, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.xunlei.adlibrary.analytics.xunlei.AdStatHelper", loadPackageParam.classLoader, "init", Context.class, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.android.fileexplorer.video.upload.VideoItemManager", loadPackageParam.classLoader, "initLoad", XC_MethodReplacement.returnConstant(null)); return; } if (loadPackageParam.packageName.equals("com.miui.player")) { Class<?> clsListener = XpUtils.findClass(loadPackageParam.classLoader, "com.android.volley.Response$Listener"); Class<?> clsErrorListener = XpUtils.findClass( loadPackageParam.classLoader, "com.android.volley.Response$ErrorListener"); Class<?> clsAdInfo = XpUtils.findClass(loadPackageParam.classLoader, "com.miui.player.util.AdUtils$AdInfo"); XpUtils.findAndHookMethod( "com.miui.player.util.AdUtils", loadPackageParam.classLoader, "isAdEnable", XC_MethodReplacement.returnConstant(false)); if (clsListener != null && clsErrorListener != null) { XpUtils.findAndHookMethod( "com.miui.player.util.AdUtils", loadPackageParam.classLoader, "getPlayAd", clsListener, clsErrorListener, XC_MethodReplacement.returnConstant(null)); } XpUtils.findAndHookMethod( "com.miui.player.util.ExperimentsHelper", loadPackageParam.classLoader, "isAdEnabled", XC_MethodReplacement.returnConstant(false)); if (clsAdInfo != null) { XpUtils.findAndHookMethod( "com.miui.player.util.AdUtils", loadPackageParam.classLoader, "handleDeepLinkUrl", Activity.class, clsAdInfo, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.miui.player.util.AdUtils", loadPackageParam.classLoader, "showAlertAndDownload", Activity.class, clsAdInfo, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.miui.player.util.AdUtils", loadPackageParam.classLoader, "handleAdClick", Activity.class, clsAdInfo, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.miui.player.util.AdUtils", loadPackageParam.classLoader, "postPlayAdStat", String.class, clsAdInfo, XC_MethodReplacement.returnConstant(null)); } XpUtils.findAndHookMethod( "com.miui.player.phone.view.NowplayingAlbumPage", loadPackageParam.classLoader, "getPlayAd", XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.miui.player.util.Configuration", loadPackageParam.classLoader, "isCmTest", XC_MethodReplacement.returnConstant(true)); XpUtils.findAndHookMethod( "com.miui.player.util.Configuration", loadPackageParam.classLoader, "isCpLogoVisiable", XC_MethodReplacement.returnConstant(false)); return; } if (loadPackageParam.packageName.equals("com.android.providers.downloads.ui")) { XpUtils.findAndHookMethod( "com.android.providers.downloads.ui.recommend.config.ADConfig", loadPackageParam.classLoader, "OSSupportAD", new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { paramAnonymousMethodHookParam.setResult(false); } }); XpUtils.findAndHookMethod( "com.android.providers.downloads.ui.utils.BuildUtils", loadPackageParam.classLoader, "isCmTestBuilder", XC_MethodReplacement.returnConstant(true)); return; } if (loadPackageParam.packageName.equals("com.miui.weather2")) { XpUtils.findAndHookMethod( "com.miui.weather2.tools.ToolUtils", loadPackageParam.classLoader, "checkCommericalStatue", Context.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { paramAnonymousMethodHookParam.setResult(false); } }); XpUtils.findAndHookMethod( "com.miui.weather2.tools.ToolUtils", loadPackageParam.classLoader, "canRequestCommercialInfo", Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.miui.weather2.tools.ToolUtils", loadPackageParam.classLoader, "checkCommericalStatue", Context.class, XC_MethodReplacement.returnConstant(false)); return; } if (loadPackageParam.packageName.equals("com.android.quicksearchbox")) { XpUtils.findAndHookMethod( "com.android.quicksearchbox.ui.LocalListView", loadPackageParam.classLoader, "updateHotQuery", List.class, int.class, new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { return null; } }); XpUtils.findAndHookMethod( "com.android.quicksearchbox.util.HotWordsUtil", loadPackageParam.classLoader, "setHotQueryView", "com.android.quicksearchbox.ui.HotQueryView", new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { paramAnonymousMethodHookParam.setResult(null); } }); return; } if (loadPackageParam.packageName.equals("com.android.mms")) { XpUtils.findAndHookMethod( "com.android.mms.ui.MessageUtils", loadPackageParam.classLoader, "isMessagingTemplateAllowed", Context.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam paramAnonymousMethodHookParam) throws Throwable { Context mc = (Context) paramAnonymousMethodHookParam.args[0]; paramAnonymousMethodHookParam.setResult( !mc.getClass().getName().toLowerCase().contains("app")); } }); XpUtils.findAndHookMethod( "com.android.mms.ui.SingleRecipientConversationActivity", loadPackageParam.classLoader, "showMenuMode", new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { return null; } }); XpUtils.findAndHookMethod( "com.android.mms.util.MiStatSdkHelper", loadPackageParam.classLoader, "recordBottomMenuShown", String.class, new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { return null; } }); } if (loadPackageParam.packageName.equals("com.miui.systemAdSolution")) { XpUtils.findAndHookMethod( "com.xiaomi.ad.internal.common.b.c", loadPackageParam.classLoader, "a", String.class, Context.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.xiaomi.ad.internal.common.b.c", loadPackageParam.classLoader, "j", Context.class, String.class, XC_MethodReplacement.returnConstant(false)); XpUtils.findAndHookMethod( "com.xiaomi.ad.internal.common.b.d", loadPackageParam.classLoader, "m", Context.class, String.class, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.miui.systemAdSolution.landingPage.h", loadPackageParam.classLoader, "a", String.class, String.class, int.class, XC_MethodReplacement.returnConstant(null)); Class<?> clsB = XpUtils.findClass(loadPackageParam.classLoader, "com.xiaomi.ad.internal.pojo.b"); if (clsB != null) { XpUtils.findAndHookMethod( "com.xiaomi.ad.internal.server.h", loadPackageParam.classLoader, "a", clsB, Bundle.class, XC_MethodReplacement.returnConstant(null)); XpUtils.findAndHookMethod( "com.xiaomi.ad.internal.server.h", loadPackageParam.classLoader, "b", clsB, Bundle.class, XC_MethodReplacement.returnConstant(null)); } XpUtils.findAndHookMethod( "com.xiaomi.ad.internal.ui.SplashAdView", loadPackageParam.classLoader, "onAction", String.class, XC_MethodReplacement.returnConstant(null)); return; } }
/* Main */ public class Main implements IXposedHookLoadPackage, IXposedHookZygoteInit, IXposedHookInitPackageResources{ private static String MODULE_PATH = null; //模块所在路径 private static String PACKAGE_NAME = "com.android.systemui"; //系统UI的包名 private static String HOOK_CLASS = "com.android.systemui.statusbar.policy.DateView"; //要Hook的Class名 private static String UPDATE_FUNC = "updateClock"; //更新函数名 private static String INTENT_SETTING_CHANGED = "de.xiaoxia.xstatusbarlunardate.SETTING_CHANGED"; //更改设置事件 private static String INTENT_SETTING_TOAST = "de.xiaoxia.xstatusbarlunardate.SETTING_TOAST"; //显示吐司 /* 初始变量 */ /* private static String lunarText = "LUNAR"; //记录最后更新时的文字字符串 private static String lDate = "LAST"; //上次记录的日期 private static String finalText = "FINALTEXT"; //最终输出的文本 private static String nDate; //当前状态栏的日期文字*/ private static String lunarTextToast = ""; //最终输出文本仅节日 private static Boolean layout_run = false; //判断是否设置过singleLine属性 // private static TextView mDateView = null; //状态栏日期的 TextView private static Set<TextView> mDateViews = new HashSet<>(); private static Context mContext = null; //显示Toast、注册接收器和获取系统服务所必需的context private static Boolean isFest = false; //今天是否为节日的标记 private static KeyguardManager km = null; //锁屏管理器,用来获取锁屏状态 private static PowerManager pm = null; //电源管理器,用来获取亮屏状态 private static Vibrator vibrator = null; //震动 private static int _notify_times_setting = 0; //记录设置好的提醒次数 /* 读取设置 */ //使用Xposed提供的XSharedPreferences方法来读取android内置的SharedPreferences设置 private final static XSharedPreferences prefs = new XSharedPreferences(Main.class.getPackage().getName()); /* 将设置保存到变量中,以备后用 */ protected static Boolean _remove_all = prefs.getBoolean("remove_all", false); //允许布局调整 protected static Boolean _remove = prefs.getBoolean("remove", false); //删除换行 protected static Boolean _term = prefs.getBoolean("term", true); //显示节气 protected static Boolean _fest = prefs.getBoolean("fest", true); //显示农历节日 protected static Boolean _custom = prefs.getBoolean("custom", false); //显示自定义农历节日 protected static Boolean _solar = prefs.getBoolean("solar", true); //显示公历节日 protected static Boolean _solar_custom = prefs.getBoolean("solar_cutom", true); //显示自定义公历节日 protected static Boolean _breakline = prefs.getBoolean("breakline", true); //另起一行 protected static Boolean _layout_enable = prefs.getBoolean("layout_enable", false); //允许布局调整 protected static Boolean _layout_line = prefs.getBoolean("layout_line", false); //允许布局调整单行 protected static Boolean _layout_width = prefs.getBoolean("layout_width", false); //允许布局调整宽度 protected static Boolean _layout_height = prefs.getBoolean("layout_height", false); //允许布局调整高度 protected static Boolean _layout_align = prefs.getBoolean("layout_align", false); //允许布局调整对齐 protected static String _custom_format = prefs.getString("custom_format", ""); //自定义状态栏字符串 protected static int _minor = Integer.valueOf(prefs.getString("minor", "1")).intValue(); //小年选项,将字符串型转换为整数型 protected static int _lang = Integer.valueOf(prefs.getString("lang", "1")).intValue(); //语言选项,将字符串型转换为整数型 protected static int _format = Integer.valueOf(prefs.getString("format", "1")).intValue(); //显示格式选项,将字符串型转换为整数型 protected static int _rom = Integer.valueOf(prefs.getString("rom", "1")).intValue(); //系统类型选项,将字符串型转换为整数型 protected static int _notify = Integer.valueOf(prefs.getString("notify", "1")).intValue(); //通知方法 protected static int _notify_times = Integer.valueOf(prefs.getString("notify_times", "1")).intValue(); //通知次数 protected static Boolean _notify_center = prefs.getBoolean("notify_center", false); //通知居中 protected static Boolean _notify_icon = prefs.getBoolean("notify_icon", false); //显示图标 protected static Boolean _notify_comp = prefs.getBoolean("notify_comp", false); //兼容性 protected static Boolean _notify_vibration = prefs.getBoolean("notify_vibration", false); //震动 protected static Boolean _lockscreen = prefs.getBoolean("lockscreen", false); //开启添加到锁屏 protected static int _lockscreen_layout = Integer.valueOf(prefs.getString("lockscreen_layout", "1")).intValue(); //锁屏布局,将字符串型转换为整数型 protected static int _lockscreen_alignment = Integer.valueOf(prefs.getString("lockscreen_alignment", "1")).intValue(); //锁屏对齐,将字符串型转换为整数型 protected static int _lockscreen_format = Integer.valueOf(prefs.getString("lockscreen_format", "1")).intValue(); //显示格式选项,将字符串型转换为整数型 protected static String _lockscreen_custom_format = prefs.getString("lockscreen_custom_format", ""); //自定义锁屏字符串 //读取自定义农历纪念日,并放入到一个数组中 protected static String[] clf = { prefs.getString("custom_lunar_item_0", "").trim(), prefs.getString("custom_lunar_item_1", "").trim(), prefs.getString("custom_lunar_item_2", "").trim(), prefs.getString("custom_lunar_item_3", "").trim(), prefs.getString("custom_lunar_item_4", "").trim(), prefs.getString("custom_lunar_item_5", "").trim(), prefs.getString("custom_lunar_item_6", "").trim(), prefs.getString("custom_lunar_item_7", "").trim(), prefs.getString("custom_lunar_item_8", "").trim(), prefs.getString("custom_lunar_item_9", "").trim(), prefs.getString("custom_lunar_item_10", "").trim(), prefs.getString("custom_lunar_item_11", "").trim(), prefs.getString("custom_lunar_item_12", "").trim(), prefs.getString("custom_lunar_item_13", "").trim(), prefs.getString("custom_lunar_item_14", "").trim(), prefs.getString("custom_lunar_item_15", "").trim(), prefs.getString("custom_lunar_item_16", "").trim(), prefs.getString("custom_lunar_item_17", "").trim(), prefs.getString("custom_lunar_item_18", "").trim(), prefs.getString("custom_lunar_item_19", "").trim() }; //读取自定义公历纪念日,并放入到一个数组中 protected static String[] csf = { prefs.getString("custom_solar_item_0", "").trim(), prefs.getString("custom_solar_item_1", "").trim(), prefs.getString("custom_solar_item_2", "").trim(), prefs.getString("custom_solar_item_3", "").trim(), prefs.getString("custom_solar_item_4", "").trim(), prefs.getString("custom_solar_item_5", "").trim(), prefs.getString("custom_solar_item_6", "").trim(), prefs.getString("custom_solar_item_7", "").trim(), prefs.getString("custom_solar_item_8", "").trim(), prefs.getString("custom_solar_item_9", "").trim(), prefs.getString("custom_solar_item_10", "").trim(), prefs.getString("custom_solar_item_11", "").trim(), prefs.getString("custom_solar_item_12", "").trim(), prefs.getString("custom_solar_item_13", "").trim(), prefs.getString("custom_solar_item_14", "").trim(), prefs.getString("custom_solar_item_15", "").trim(), prefs.getString("custom_solar_item_16", "").trim(), prefs.getString("custom_solar_item_17", "").trim(), prefs.getString("custom_solar_item_18", "").trim(), prefs.getString("custom_solar_item_19", "").trim() }; //初始化Lunar类 private static Lunar lunar; /* 向Systemui注入图标和字符串资源*/ private static int ic_toast_bg_fest; private static int ic_toast_bg; @Override public void initZygote(StartupParam startupParam){ MODULE_PATH = startupParam.modulePath; //获取模块实际路径 } @Override public void handleInitPackageResources(InitPackageResourcesParam resparam){ if (!resparam.packageName.equals(PACKAGE_NAME)) return; //如果不是UI则跳过 //这里将自带的图标资源插入到systemui中,并获取到一个资源id XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res); //创建一个插入资源的实例 ic_toast_bg_fest = resparam.res.addResource(modRes, R.drawable.ic_toast_bg_fest); ic_toast_bg = resparam.res.addResource(modRes, R.drawable.ic_toast_bg); } /* 替换日期函数 */ @Override public void handleLoadPackage(final LoadPackageParam lpparam){ if(!lpparam.packageName.equals(PACKAGE_NAME)) return; //如果不是UI则跳过 lunar = new Lunar(Main._lang); //初始化Lunar类 _notify_times_setting = _notify_times; //记录提醒次数 //如果打开了调整布局,则允许进入调整布局步骤 if(!_layout_enable) layout_run = true; //根据rom类型选择正确的更新函数 switch(_rom){ case 1: break; //原生Android的日起更新函数名 case 2: UPDATE_FUNC = "a"; break; //Miui 4.4 之前的系统更新时间的函数名称为“a” case 3: HOOK_CLASS = "com.android.systemui.statusbar.policy.QuickSettingsDateView"; break; //Asus Zenfone6 } //勾在com.android.systemui.statusbar.policy.DateView里面的updateClock()之后 //这的函数可以参考 https://github.com/rovo89/XposedBridge/wiki/Development-tutorial,比较简单 findAndHookMethod(HOOK_CLASS, lpparam.classLoader, UPDATE_FUNC, new XC_MethodHook() { @Override //在原函数执行完之后再执行自定义程序 protected void afterHookedMethod(MethodHookParam param){ //获取原文字,com.android.systemui.statusbar.policy.DateView类是extends于TextView TextView dateView = (TextView) param.thisObject; //获取这个对象 synchronized (Main.class) { mDateViews.add(dateView); } mContext = dateView.getContext(); //获取上下文 if(mContext != null) registerReceiver(mContext); //注册接收器 setText();//交给setText处理 } }); } /* 获取农历字符串子程序 */ private void setText(){ synchronized (Main.class) { for (TextView dateView : mDateViews) { /* 判断当前日期栏是否包含上次更新后的日期文本 * 如果当前日期已经改变,则必须重新计算农历 * 如果当前日期未改变,则只需要重新用已经缓存的文本写入TextView */ //判断日期是否改变,不改变则不更新内容,改变则重新计算农历 String nDate = dateView.getText().toString(); String lDate = (String) XposedHelpers.getAdditionalInstanceField(dateView, "lDate"); String lunarText = (String) XposedHelpers.getAdditionalInstanceField(dateView, "lunarText"); String finalText = (String) XposedHelpers.getAdditionalInstanceField(dateView, "finalText"); if (lunarText == null || !(nDate.contains(lunarText) || finalText == null || nDate.equals(finalText))) { if (lDate == null || !nDate.equals(lDate)) { //获取时间 lunar.init(); //修正layout的singleLine属性 if (!layout_run) { try { //去掉singleLine属性 if (_layout_line) dateView.setSingleLine(false); //去除singleLine属性 //去掉align_baseline,并将其设置为center_vertical if (_layout_align) { //一般机型的状态栏都是RelativeLayout,少数为LinearLayout,但似乎影响不大 RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) dateView.getLayoutParams(); layoutParams.addRule(RelativeLayout.ALIGN_BASELINE, 0); //去除baseline对齐属性 layoutParams.addRule(RelativeLayout.CENTER_VERTICAL); //并将其设置为绝对居中 dateView.setLayoutParams(layoutParams); //设置布局参数 } //设置宽度为wrap_content if (_layout_width) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) dateView.getLayoutParams(); layoutParams.width = LayoutParams.WRAP_CONTENT; //取消宽度限制 dateView.setLayoutParams(layoutParams); } //设置高度为wrap_content if (_layout_height) { RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) dateView.getLayoutParams(); layoutParams.height = LayoutParams.WRAP_CONTENT; //取消高度限制 dateView.setLayoutParams(layoutParams); } layout_run = true; //已经执行过布局的处理步骤,下次不再执行 } catch (Throwable t) { XposedBridge.log("xStatusBarLunarDate: Statusbar layout fix error:"); XposedBridge.log(t); } } //更新记录的日期 XposedHelpers.setAdditionalInstanceField(dateView, "lDate", nDate); //从Lunar类中获得组合好的农历日期字符串(包括各节日) lunarText = lunar.getFormattedDate(_custom_format, _format); XposedHelpers.setAdditionalInstanceField(dateView, "lunarText", lunarText); //重置提醒次数 _notify_times = _notify_times_setting; if (_notify > 1) { //当天是否是节日 isFest = !"".equals(lunar.getFormattedDate("ff", 5)); if ((isFest || _notify == 2) && _lang != 3) { lunarTextToast = nDate.trim().replaceAll("\\n", " ") + "\n" + (_format == 5 ? lunar.getFormattedDate("", 3) : lunarText); } else { lunarTextToast = ""; } } //组合最终显示的文字 finalText = _remove_all ? lunarText : (_remove ? nDate.trim().replaceAll("[\\n|\\r]", " ") : nDate) + (_breakline ? "\n" : " ") + lunarText; XposedHelpers.setAdditionalInstanceField(dateView, "finalText", finalText); } //向TextView设置显示的最终文字 dateView.setText(finalText); } } } } //震动控制 private void makeVibration(Context context){ if(vibrator == null) vibrator = (Vibrator)context.getSystemService(Service.VIBRATOR_SERVICE); if(isFest && _notify_vibration) //仅当有节日且开启时才震动 vibrator.vibrate(250); } //显示 Toast private void makeToast(Context context){ if("".equals(lunarTextToast)) return; try{ Toast toast = Toast.makeText(context, lunarTextToast, Toast.LENGTH_LONG); if(_notify_comp){ //如果打开了美化 LinearLayout toastView = (LinearLayout) toast.getView(); //尝试寻找toastView布局中的textView节点 TextView toastTextView; try{ toastTextView = (TextView) toastView.getChildAt(0); }catch(Throwable t){ try { toastTextView = (TextView) toastView.getChildAt(1); } catch (Throwable tt) { toastTextView = null; } } if(toastTextView != null){ toastTextView.setGravity(Gravity.CENTER_HORIZONTAL); //调整Toast为文字居中 toastTextView.setLineSpacing(0, 1.2f); //调整Toast文字行间距为原来的1.2倍 } if(_notify_center) //Toast在屏幕正中显示 toast.setGravity(Gravity.CENTER, 0, 0); if(_notify_icon){ //为Toast加入背景 toastView.setBackground((context.getResources().getDrawable(isFest ? ic_toast_bg_fest : ic_toast_bg))); toastView.setGravity(Gravity.CENTER); if(toastTextView != null){ toastTextView.setTextColor(0xFF000000); toastTextView.setPadding(0, 15, 0, 0); toastTextView.setShadowLayer(0, 0, 0, 0X00FFFFFF); } } } toast.show(); makeVibration(context); }catch(Throwable t){ XposedBridge.log("xStatusBarLunarDate: Toast error:"); XposedBridge.log(t); } } //重置日期记录信息 private void resetLast(){ synchronized (Main.class) { for (TextView dateView : mDateViews) { XposedHelpers.setAdditionalInstanceField(dateView, "lunarText", "RESET"); XposedHelpers.setAdditionalInstanceField(dateView, "finalText", "RESET"); XposedHelpers.setAdditionalInstanceField(dateView, "lDate", "RESET"); //4.4以上有个mLastText储存上次的日期字符串,在此尝试清空它,避免导致文字出现重复等现象 if(Build.VERSION.SDK_INT >= 19){ try{ XposedHelpers.setObjectField(dateView, "mLastText", ""); //重置DateView内部日期记录 }catch(Throwable t){} } } } } //注册接收器 private void registerReceiver(Context context){ IntentFilter intent = new IntentFilter(); intent.addAction(Intent.ACTION_USER_PRESENT); //注册解锁屏幕事件 intent.addAction(Intent.ACTION_SCREEN_ON); //注册亮屏事件 intent.addAction(Intent.ACTION_DATE_CHANGED); //注册日期变更事件 intent.addAction(Intent.ACTION_TIMEZONE_CHANGED); //注册时区变更事件 intent.addAction(INTENT_SETTING_CHANGED); //注册设置变更事件 intent.addAction(INTENT_SETTING_TOAST); //注册显示Toast事件 context.registerReceiver(xReceiver, intent); } //广播接收处理 private BroadcastReceiver xReceiver = new BroadcastReceiver() { @SuppressWarnings("deprecation") @Override public void onReceive(Context context, Intent intent) { context = mContext; if(km == null) km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); if(pm == null) pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); //Intent事件判断 if(intent.getAction().equals(INTENT_SETTING_CHANGED)){ //如果用户更改了设置,从intent中读取更改过的设置 _remove_all = intent.getExtras().getBoolean("remove_all", _remove_all); _remove = intent.getExtras().getBoolean("remove", _remove); _term = intent.getExtras().getBoolean("term", _term); _fest = intent.getExtras().getBoolean("fest", _fest); _custom = intent.getExtras().getBoolean("custom", _custom); _solar = intent.getExtras().getBoolean("solar", _solar); _solar_custom = intent.getExtras().getBoolean("solar_cutom", _solar_custom); _breakline = intent.getExtras().getBoolean("breakline", _breakline); _layout_enable = intent.getExtras().getBoolean("layout_enable", _layout_enable); _layout_line = intent.getExtras().getBoolean("layout_line", _layout_line); _layout_width = intent.getExtras().getBoolean("layout_width", _layout_width); _layout_align = intent.getExtras().getBoolean("layout_align", _layout_align); _layout_height = intent.getExtras().getBoolean("layout_height", _layout_height); _custom_format = intent.getExtras().getString("custom_format", _custom_format); _minor = intent.getExtras().getInt("minor", _minor); _lang = intent.getExtras().getInt("lang", _lang); _format = intent.getExtras().getInt("format", _format); _notify = intent.getExtras().getInt("notify", _notify); _notify_times_setting = _notify_times = intent.getExtras().getInt("notify_times", _notify_times_setting); _notify_center = intent.getExtras().getBoolean("notify_center", _notify_center); _notify_icon = intent.getExtras().getBoolean("notify_icon", _notify_icon); _notify_comp = intent.getExtras().getBoolean("notify_comp", _notify_comp); _notify_vibration = intent.getExtras().getBoolean("notify_vibration", _notify_vibration); for(int i = 0; i <= 14; i++){ clf[i] = intent.getExtras().getString("custom_lunar_item_" + i, clf[i]); csf[i] = intent.getExtras().getString("custom_solar_item_" + i, csf[i]); } //重置一些变量 if(!_layout_enable) layout_run = true; resetLast(); lunar = new Lunar(_lang); callUpdateFuncs(); //强制执行日期更新函数 }else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)){ //如果用户亮屏且屏幕处于未解锁状态 if(!km.inKeyguardRestrictedInputMode() && _notify_times > 0){ makeToast(context); _notify_times--; } }else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT)){ //如果用户解锁屏幕 if(_notify_times > 0){ makeToast(context); _notify_times--; } }else if(intent.getAction().equals(Intent.ACTION_DATE_CHANGED)){ //如果日期变更且用户处于亮屏状态 resetLast(); callUpdateFuncs(); //强制执行日期更新函数 if(pm.isScreenOn() && !km.inKeyguardRestrictedInputMode()) makeToast(context); }else if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)){ //如果时区变更 resetLast(); lunar = new Lunar(_lang); callUpdateFuncs(); //强制执行日期更新函数 makeToast(context); }else if(intent.getAction().equals(INTENT_SETTING_TOAST)){ if(_notify != 2){ //改为总是弹出,强制更新,再改回去,强制更新 int _notify_temp = _notify; //设置一个临时变量记录初始状态 _notify = 2; //设置为总是弹出通知 resetLast(); callUpdateFuncs(); //强制执行日期更新函数 makeToast(context); _notify = _notify_temp; // 吐司通知设置复位到初始状态 lunarTextToast = ""; // 清空Toast文字,避免其它情况再次显示 resetLast(); callUpdateFuncs(); }else{ makeToast(context); } } } }; private void callUpdateFuncs() { synchronized (Main.class) { for (TextView dateView : mDateViews) XposedHelpers.callMethod(dateView, UPDATE_FUNC); } } }