├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml ├── ccache.sh └── workflows │ ├── build.yml │ └── issues.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.MD ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro ├── shared │ ├── .gitignore │ ├── build.gradle.kts │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── topjohnwu │ │ └── magisk │ │ ├── DynAPK.java │ │ ├── FileProvider.java │ │ ├── ProviderInstaller.java │ │ └── utils │ │ ├── APKInstall.java │ │ ├── CompoundEnumeration.java │ │ └── DynamicClassLoader.java └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── topjohnwu │ │ └── magisk │ │ ├── arch │ │ ├── BaseUIActivity.kt │ │ ├── BaseUIComponent.kt │ │ ├── BaseUIFragment.kt │ │ ├── BaseViewModel.kt │ │ ├── Queryable.kt │ │ └── ViewEvent.kt │ │ ├── core │ │ ├── App.kt │ │ ├── Config.kt │ │ ├── Const.kt │ │ ├── Hacks.kt │ │ ├── Info.kt │ │ ├── Provider.kt │ │ ├── Receiver.kt │ │ ├── SplashActivity.kt │ │ ├── UpdateCheckService.kt │ │ ├── base │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseReceiver.kt │ │ │ ├── BaseService.kt │ │ │ ├── BaseWorkerWrapper.kt │ │ │ └── PermissionRequestBuilder.kt │ │ ├── download │ │ │ ├── BaseDownloader.kt │ │ │ ├── DownloadService.kt │ │ │ ├── ManagerHandler.kt │ │ │ ├── ModuleProcessor.kt │ │ │ └── Subject.kt │ │ ├── magiskdb │ │ │ ├── BaseDao.kt │ │ │ ├── PolicyDao.kt │ │ │ ├── Query.kt │ │ │ ├── SettingsDao.kt │ │ │ └── StringDao.kt │ │ ├── model │ │ │ ├── UpdateInfo.kt │ │ │ ├── module │ │ │ │ ├── LocalModule.kt │ │ │ │ ├── Module.kt │ │ │ │ └── OnlineModule.kt │ │ │ └── su │ │ │ │ ├── SuLog.kt │ │ │ │ └── SuPolicy.kt │ │ ├── su │ │ │ ├── SuCallbackHandler.kt │ │ │ └── SuRequestHandler.kt │ │ ├── tasks │ │ │ ├── FlashZip.kt │ │ │ ├── HideAPK.kt │ │ │ ├── MagiskInstaller.kt │ │ │ └── RepoUpdater.kt │ │ └── utils │ │ │ ├── AXML.kt │ │ │ ├── BiometricHelper.kt │ │ │ ├── IODispatcherExecutor.kt │ │ │ ├── Keygen.kt │ │ │ ├── Locales.kt │ │ │ ├── MediaStoreUtils.kt │ │ │ ├── ProgressInputStream.kt │ │ │ ├── ShellInit.kt │ │ │ ├── ZipUtils.kt │ │ │ └── net │ │ │ ├── LollipopNetworkObserver.kt │ │ │ ├── MarshmallowNetworkObserver.kt │ │ │ └── NetworkObserver.kt │ │ ├── data │ │ ├── database │ │ │ ├── RepoDao.kt │ │ │ └── SuLogDao.kt │ │ ├── network │ │ │ └── NetworkServices.kt │ │ ├── preference │ │ │ ├── BooleanProperty.kt │ │ │ ├── FloatProperty.kt │ │ │ ├── IntProperty.kt │ │ │ ├── LongProperty.kt │ │ │ ├── PreferenceModel.kt │ │ │ ├── Property.kt │ │ │ ├── StringProperty.kt │ │ │ └── StringSetProperty.kt │ │ └── repository │ │ │ ├── DBConfig.kt │ │ │ ├── LogRepository.kt │ │ │ └── NetworkService.kt │ │ ├── databinding │ │ ├── AdaptersRecycler.kt │ │ ├── BindingBoundAdapter.kt │ │ ├── DataBindingAdapters.kt │ │ ├── DiffObservableList.kt │ │ ├── FilterableDiffObservableList.kt │ │ ├── Helpers.kt │ │ ├── ObservableHost.kt │ │ ├── RecyclerViewItems.kt │ │ └── RvBindingAdapter.kt │ │ ├── di │ │ ├── Networking.kt │ │ └── ServiceLocator.kt │ │ ├── events │ │ ├── OpenInappLinkEvent.kt │ │ ├── RebootEvent.kt │ │ ├── SnackbarEvent.kt │ │ ├── ViewEvents.kt │ │ └── dialog │ │ │ ├── BiometricEvent.kt │ │ │ ├── DarkThemeDialog.kt │ │ │ ├── DialogEvent.kt │ │ │ ├── EnvFixDialog.kt │ │ │ ├── ManagerInstallDialog.kt │ │ │ ├── MarkDownDialog.kt │ │ │ ├── ModuleInstallDialog.kt │ │ │ ├── SecondSlotWarningDialog.kt │ │ │ ├── SuperuserRevokeDialog.kt │ │ │ └── UninstallDialog.kt │ │ ├── ktx │ │ ├── Dimens.kt │ │ ├── RecyclerView.kt │ │ ├── XAndroid.kt │ │ ├── XBinding.kt │ │ ├── XJava.kt │ │ ├── XSU.kt │ │ └── XString.kt │ │ ├── signing │ │ ├── ApkSignerV2.java │ │ ├── ByteArrayStream.java │ │ ├── CryptoUtils.java │ │ ├── JarMap.java │ │ ├── SignApk.java │ │ ├── SignBoot.java │ │ └── ZipUtils.java │ │ ├── ui │ │ ├── MainActivity.kt │ │ ├── flash │ │ │ ├── ConsoleItem.kt │ │ │ ├── FlashFragment.kt │ │ │ └── FlashViewModel.kt │ │ ├── hide │ │ │ ├── HideFragment.kt │ │ │ ├── HideInfo.kt │ │ │ ├── HideRvItems.kt │ │ │ └── HideViewModel.kt │ │ ├── home │ │ │ ├── DeveloperItem.kt │ │ │ ├── HomeFragment.kt │ │ │ └── HomeViewModel.kt │ │ ├── inflater │ │ │ ├── LayoutInflaterFactory.kt │ │ │ └── WindowInsetsHelper.kt │ │ ├── install │ │ │ ├── InstallFragment.kt │ │ │ └── InstallViewModel.kt │ │ ├── log │ │ │ ├── LogFragment.kt │ │ │ ├── LogRvItem.kt │ │ │ └── LogViewModel.kt │ │ ├── module │ │ │ ├── ModuleFragment.kt │ │ │ ├── ModuleRvItem.kt │ │ │ └── ModuleViewModel.kt │ │ ├── safetynet │ │ │ ├── CheckSafetyNetEvent.kt │ │ │ ├── SafetyNetHelper.kt │ │ │ ├── SafetynetFragment.kt │ │ │ └── SafetynetViewModel.kt │ │ ├── settings │ │ │ ├── BaseSettingsItem.kt │ │ │ ├── SettingsFragment.kt │ │ │ ├── SettingsItems.kt │ │ │ └── SettingsViewModel.kt │ │ ├── superuser │ │ │ ├── PolicyRvItem.kt │ │ │ ├── SuperuserFragment.kt │ │ │ └── SuperuserViewModel.kt │ │ ├── surequest │ │ │ ├── SuRequestActivity.kt │ │ │ └── SuRequestViewModel.kt │ │ └── theme │ │ │ ├── Theme.kt │ │ │ ├── ThemeFragment.kt │ │ │ └── ThemeViewModel.kt │ │ ├── utils │ │ ├── CachedValue.kt │ │ ├── EndlessRecyclerScrollListener.kt │ │ ├── HideableBehavior.kt │ │ ├── KItemDecoration.kt │ │ ├── MarkwonImagePlugin.kt │ │ ├── MotionRevealHelper.kt │ │ ├── TextHolder.kt │ │ └── Utils.kt │ │ └── view │ │ ├── MagiskDialog.kt │ │ ├── Notifications.kt │ │ ├── Shortcuts.kt │ │ ├── TappableHeadlineItem.kt │ │ └── TextItem.kt │ └── res │ ├── anim │ ├── fragment_enter.xml │ ├── fragment_enter_pop.xml │ ├── fragment_exit.xml │ └── fragment_exit_pop.xml │ ├── color │ ├── color_error_transient.xml │ ├── color_menu_tint.xml │ ├── color_on_primary_transient.xml │ ├── color_primary_error_transient.xml │ ├── color_primary_transient.xml │ ├── color_secondary_transient.xml │ ├── color_state_primary_transient.xml │ └── color_text_transient.xml │ ├── drawable-nodpi │ └── logo.png │ ├── drawable-v23 │ └── ic_splash_activity.xml │ ├── drawable-v26 │ ├── ic_launcher.xml │ ├── sc_extension.xml │ ├── sc_magiskhide.xml │ └── sc_superuser.xml │ ├── drawable │ ├── avd_bug_from_filled.xml │ ├── avd_bug_to_filled.xml │ ├── avd_circle_check_from_filled.xml │ ├── avd_circle_check_to_filled.xml │ ├── avd_delete_magisk.xml │ ├── avd_home_from_filled.xml │ ├── avd_home_to_filled.xml │ ├── avd_magisk_delete.xml │ ├── avd_module_from_filled.xml │ ├── avd_module_to_filled.xml │ ├── avd_settings_from_filled.xml │ ├── avd_settings_to_filled.xml │ ├── avd_superuser_from_filled.xml │ ├── avd_superuser_to_filled.xml │ ├── bg_checkbox.xml │ ├── bg_divider_rounded_on_primary.xml │ ├── bg_line_bottom_rounded.xml │ ├── bg_line_top_rounded.xml │ ├── bg_selection_circle_green.xml │ ├── bg_shadow.xml │ ├── divider_l1.xml │ ├── divider_l_50.xml │ ├── ic_back_md2.xml │ ├── ic_bug_filled_md2.xml │ ├── ic_bug_md2.xml │ ├── ic_bug_outlined_md2.xml │ ├── ic_check_circle_checked_md2.xml │ ├── ic_check_circle_md2.xml │ ├── ic_check_circle_unchecked_md2.xml │ ├── ic_check_md2.xml │ ├── ic_checkbox.xml │ ├── ic_close_md2.xml │ ├── ic_compound_checkbox.xml │ ├── ic_day.xml │ ├── ic_day_night.xml │ ├── ic_delete_md2.xml │ ├── ic_device.xml │ ├── ic_download_md2.xml │ ├── ic_extension.xml │ ├── ic_fingerprint.xml │ ├── ic_folder_list.xml │ ├── ic_forth_md2.xml │ ├── ic_github.xml │ ├── ic_hide_md2.xml │ ├── ic_hide_select_md2.xml │ ├── ic_home_filled_md2.xml │ ├── ic_home_md2.xml │ ├── ic_home_outlined_md2.xml │ ├── ic_info.xml │ ├── ic_install.xml │ ├── ic_logo.xml │ ├── ic_magisk.xml │ ├── ic_magisk_delete.xml │ ├── ic_magisk_outline.xml │ ├── ic_magisk_padded.xml │ ├── ic_magiskhide.xml │ ├── ic_manager.xml │ ├── ic_module_filled_md2.xml │ ├── ic_module_md2.xml │ ├── ic_module_outlined_md2.xml │ ├── ic_module_storage_md2.xml │ ├── ic_more.xml │ ├── ic_night.xml │ ├── ic_notifications_md2.xml │ ├── ic_order_date.xml │ ├── ic_order_name.xml │ ├── ic_paint.xml │ ├── ic_patreon.xml │ ├── ic_paypal.xml │ ├── ic_refresh_data_md2.xml │ ├── ic_refresh_safetynet_md2.xml │ ├── ic_restart.xml │ ├── ic_safetynet_md2.xml │ ├── ic_save_md2.xml │ ├── ic_search_md2.xml │ ├── ic_settings_filled_md2.xml │ ├── ic_settings_md2.xml │ ├── ic_settings_outlined_md2.xml │ ├── ic_show_md2.xml │ ├── ic_splash_activity.xml │ ├── ic_superuser.xml │ ├── ic_superuser_filled_md2.xml │ ├── ic_superuser_md2.xml │ ├── ic_superuser_outlined_md2.xml │ ├── ic_twitter.xml │ ├── ic_up_md2.xml │ ├── ic_update_md2.xml │ ├── sc_extension.xml │ ├── sc_magiskhide.xml │ └── sc_superuser.xml │ ├── layout │ ├── activity_main_md2.xml │ ├── activity_request.xml │ ├── dialog_magisk_base.xml │ ├── dialog_settings_app_name.xml │ ├── dialog_settings_download_path.xml │ ├── dialog_settings_update_channel.xml │ ├── fragment_flash_md2.xml │ ├── fragment_hide_md2.xml │ ├── fragment_home_md2.xml │ ├── fragment_install_md2.xml │ ├── fragment_log_md2.xml │ ├── fragment_module_md2.xml │ ├── fragment_safetynet_md2.xml │ ├── fragment_settings_md2.xml │ ├── fragment_superuser_md2.xml │ ├── fragment_theme_md2.xml │ ├── include_hide_filter.xml │ ├── include_home_magisk.xml │ ├── include_home_manager.xml │ ├── include_log_magisk.xml │ ├── include_log_superuser.xml │ ├── include_module_filter.xml │ ├── item_console_md2.xml │ ├── item_developer.xml │ ├── item_hide_md2.xml │ ├── item_hide_process_md2.xml │ ├── item_icon_link.xml │ ├── item_list_single_line.xml │ ├── item_log_access_md2.xml │ ├── item_log_track_md2.xml │ ├── item_module_download.xml │ ├── item_module_md2.xml │ ├── item_policy_md2.xml │ ├── item_repo_md2.xml │ ├── item_section_md2.xml │ ├── item_settings.xml │ ├── item_settings_section.xml │ ├── item_spinner.xml │ ├── item_tappable_headline.xml │ ├── item_text.xml │ ├── item_theme.xml │ ├── item_theme_container.xml │ └── markdown_window_md2.xml │ ├── menu │ ├── menu_bottom_nav.xml │ ├── menu_flash.xml │ ├── menu_hide_md2.xml │ ├── menu_home_md2.xml │ ├── menu_log_md2.xml │ ├── menu_module_md2.xml │ └── menu_reboot.xml │ ├── navigation │ └── main.xml │ ├── raw │ ├── changelog.md │ └── manager.sh │ ├── values-ar │ └── strings.xml │ ├── values-az │ └── strings.xml │ ├── values-be │ └── strings.xml │ ├── values-bg │ └── strings.xml │ ├── values-ca │ └── strings.xml │ ├── values-cs │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-el │ └── strings.xml │ ├── values-es │ └── strings.xml │ ├── values-et │ └── strings.xml │ ├── values-fa │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-hi │ └── strings.xml │ ├── values-hr │ └── strings.xml │ ├── values-in │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-iw │ └── strings.xml │ ├── values-ja │ └── strings.xml │ ├── values-ka │ └── strings.xml │ ├── values-ko │ └── strings.xml │ ├── values-lt │ └── strings.xml │ ├── values-mk │ └── strings.xml │ ├── values-nb │ └── strings.xml │ ├── values-night │ ├── colors.xml │ ├── styles_md2.xml │ └── themes_md2.xml │ ├── values-nl │ └── strings.xml │ ├── values-pa │ └── strings.xml │ ├── values-pl │ └── strings.xml │ ├── values-pt-rBR │ └── strings.xml │ ├── values-pt-rPT │ └── strings.xml │ ├── values-ro │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-sk │ └── strings.xml │ ├── values-sq │ └── strings.xml │ ├── values-sr │ └── strings.xml │ ├── values-sv │ └── strings.xml │ ├── values-ta │ └── strings.xml │ ├── values-th │ └── strings.xml │ ├── values-tr │ └── strings.xml │ ├── values-uk │ └── strings.xml │ ├── values-v23 │ └── themes.xml │ ├── values-v27 │ └── themes.xml │ ├── values-vi │ └── strings.xml │ ├── values-zh-rCN │ └── strings.xml │ ├── values-zh-rTW │ └── strings.xml │ └── values │ ├── arrays.xml │ ├── attrs.xml │ ├── colors.xml │ ├── default_color.xml │ ├── dimens.xml │ ├── drawable.xml │ ├── ids.xml │ ├── resources.xml │ ├── strings.xml │ ├── styles_md2.xml │ ├── styles_md2_appearance.xml │ ├── styles_md2_impl.xml │ ├── styles_view_md2.xml │ ├── themes.xml │ └── themes_md2.xml ├── build.gradle.kts ├── build.py ├── buildSrc ├── .gitignore ├── build.gradle.kts └── src │ └── main │ └── java │ ├── Codegen.kt │ ├── Plugin.kt │ └── Setup.kt ├── config.prop.sample ├── docs ├── README.md ├── app_changes.md ├── boot.md ├── changes.md ├── deploy.md ├── details.md ├── faq.md ├── guides.md ├── images │ ├── device_info.png │ ├── disable_auto_ota.png │ ├── install_inactive_slot.png │ ├── logo.png │ ├── manager_reboot.png │ ├── ota_done.png │ └── restore_img.png ├── install.md ├── ota.md ├── procedures.html ├── releases │ ├── 18000.md │ ├── 18100.md │ ├── 19000.md │ ├── 19100.md │ ├── 19200.md │ ├── 19300.md │ ├── 19400.md │ ├── 20000.md │ ├── 20100.md │ ├── 20200.md │ ├── 20300.md │ ├── 20400.md │ ├── 21000.md │ ├── 21100.md │ ├── 21200.md │ ├── 21400.md │ ├── 22000.md │ ├── 22100.md │ ├── 23000.md │ └── index.md └── tools.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── native ├── .gitignore ├── build.gradle.kts ├── jni │ ├── .gitignore │ ├── Android.mk │ ├── Application.mk │ ├── core │ │ ├── applet_stub.cpp │ │ ├── applets.cpp │ │ ├── bootstages.cpp │ │ ├── core.hpp │ │ ├── daemon.cpp │ │ ├── db.cpp │ │ ├── logging.cpp │ │ ├── magisk.cpp │ │ ├── module.cpp │ │ ├── restorecon.cpp │ │ ├── scripting.cpp │ │ ├── socket.cpp │ │ └── thread.cpp │ ├── external │ │ ├── Android.mk │ │ ├── systemproperties │ │ │ ├── Android.mk │ │ │ ├── context_node.cpp │ │ │ ├── contexts_serialized.cpp │ │ │ ├── contexts_split.cpp │ │ │ ├── include │ │ │ │ ├── _system_properties.h │ │ │ │ ├── async_safe │ │ │ │ │ └── log.h │ │ │ │ ├── private │ │ │ │ │ ├── ErrnoRestorer.h │ │ │ │ │ ├── bionic_defs.h │ │ │ │ │ ├── bionic_futex.h │ │ │ │ │ ├── bionic_lock.h │ │ │ │ │ ├── bionic_macros.h │ │ │ │ │ └── hacks.h │ │ │ │ ├── property_info_parser │ │ │ │ │ └── property_info_parser.h │ │ │ │ ├── system_properties.h │ │ │ │ └── system_properties │ │ │ │ │ ├── context_node.h │ │ │ │ │ ├── contexts.h │ │ │ │ │ ├── contexts_pre_split.h │ │ │ │ │ ├── contexts_serialized.h │ │ │ │ │ ├── contexts_split.h │ │ │ │ │ ├── prop_area.h │ │ │ │ │ ├── prop_info.h │ │ │ │ │ └── system_properties.h │ │ │ ├── prop_area.cpp │ │ │ ├── prop_info.cpp │ │ │ ├── property_info_parser.cpp │ │ │ ├── system_properties.cpp │ │ │ ├── system_property_api.cpp │ │ │ └── system_property_set.cpp │ │ ├── xz-embedded │ │ │ ├── xz.h │ │ │ ├── xz_config.h │ │ │ ├── xz_crc32.c │ │ │ ├── xz_dec_lzma2.c │ │ │ ├── xz_dec_stream.c │ │ │ ├── xz_lzma2.h │ │ │ ├── xz_private.h │ │ │ └── xz_stream.h │ │ └── xz_config │ │ │ └── config.h │ ├── include │ │ ├── daemon.hpp │ │ ├── db.hpp │ │ ├── magisk.hpp │ │ ├── magiskpolicy.hpp │ │ ├── resetprop.hpp │ │ └── socket.hpp │ ├── init │ │ ├── getinfo.cpp │ │ ├── init.cpp │ │ ├── init.hpp │ │ ├── magiskrc.inc │ │ ├── mount.cpp │ │ ├── raw_data.cpp │ │ ├── raw_data.hpp │ │ ├── rootdir.cpp │ │ └── twostage.cpp │ ├── magiskboot │ │ ├── bootimg.cpp │ │ ├── bootimg.hpp │ │ ├── compress.cpp │ │ ├── compress.hpp │ │ ├── cpio.cpp │ │ ├── cpio.hpp │ │ ├── dtb.cpp │ │ ├── dtb.hpp │ │ ├── format.cpp │ │ ├── format.hpp │ │ ├── hexpatch.cpp │ │ ├── magiskboot.hpp │ │ ├── main.cpp │ │ ├── pattern.cpp │ │ └── ramdisk.cpp │ ├── magiskhide │ │ ├── hide_policy.cpp │ │ ├── hide_utils.cpp │ │ ├── magiskhide.cpp │ │ ├── magiskhide.hpp │ │ └── proc_monitor.cpp │ ├── magiskpolicy │ │ ├── magiskpolicy.cpp │ │ ├── policydb.cpp │ │ ├── rules.cpp │ │ ├── sepolicy.cpp │ │ ├── sepolicy.hpp │ │ └── statement.cpp │ ├── resetprop │ │ ├── _resetprop.hpp │ │ ├── persist_properties.cpp │ │ └── resetprop.cpp │ ├── su │ │ ├── connect.cpp │ │ ├── pts.cpp │ │ ├── pts.hpp │ │ ├── su.cpp │ │ ├── su.hpp │ │ └── su_daemon.cpp │ ├── utils │ │ ├── Android.mk │ │ ├── files.cpp │ │ ├── files.hpp │ │ ├── include │ │ │ ├── selinux.hpp │ │ │ ├── stream.hpp │ │ │ └── utils.hpp │ │ ├── logging.cpp │ │ ├── logging.hpp │ │ ├── misc.cpp │ │ ├── misc.hpp │ │ ├── missing.cpp │ │ ├── missing.hpp │ │ ├── new.cpp │ │ ├── selinux.cpp │ │ ├── stream.cpp │ │ ├── xwrap.cpp │ │ └── xwrap.hpp │ └── zygisk │ │ ├── api.hpp │ │ ├── entry.cpp │ │ ├── gen_jni_hooks.py │ │ ├── hook.cpp │ │ ├── inject.hpp │ │ ├── jni_hooks.hpp │ │ ├── memory.cpp │ │ ├── memory.hpp │ │ ├── ptrace.cpp │ │ ├── ptrace.hpp │ │ └── utils.cpp └── src │ └── main │ └── AndroidManifest.xml ├── scripts ├── addon.d.sh ├── boot_patch.sh ├── emulator.sh ├── flash_script.sh ├── module_installer.sh ├── uninstaller.sh ├── update_binary.sh └── util_functions.sh ├── settings.gradle.kts ├── stub ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro ├── res │ ├── values-ar │ │ └── strings.xml │ ├── values-az │ │ └── strings.xml │ ├── values-be │ │ └── strings.xml │ ├── values-bg │ │ └── strings.xml │ ├── values-ca │ │ └── strings.xml │ ├── values-cs │ │ └── strings.xml │ ├── values-de │ │ └── strings.xml │ ├── values-el │ │ └── strings.xml │ ├── values-es │ │ └── strings.xml │ ├── values-et │ │ └── strings.xml │ ├── values-fa │ │ └── strings.xml │ ├── values-fr │ │ └── strings.xml │ ├── values-hi │ │ └── strings.xml │ ├── values-hr │ │ └── strings.xml │ ├── values-in │ │ └── strings.xml │ ├── values-it │ │ └── strings.xml │ ├── values-iw │ │ └── strings.xml │ ├── values-ja │ │ └── strings.xml │ ├── values-ka │ │ └── strings.xml │ ├── values-ko │ │ └── strings.xml │ ├── values-lt │ │ └── strings.xml │ ├── values-mk │ │ └── strings.xml │ ├── values-nb │ │ └── strings.xml │ ├── values-nl │ │ └── strings.xml │ ├── values-pa │ │ └── strings.xml │ ├── values-pl │ │ └── strings.xml │ ├── values-pt-rBR │ │ └── strings.xml │ ├── values-pt-rPT │ │ └── strings.xml │ ├── values-ro │ │ └── strings.xml │ ├── values-ru │ │ └── strings.xml │ ├── values-sk │ │ └── strings.xml │ ├── values-sr │ │ └── strings.xml │ ├── values-sv │ │ └── strings.xml │ ├── values-ta │ │ └── strings.xml │ ├── values-th │ │ └── strings.xml │ ├── values-tr │ │ └── strings.xml │ ├── values-uk │ │ └── strings.xml │ ├── values-vi │ │ └── strings.xml │ ├── values-zh-rCN │ │ └── strings.xml │ ├── values-zh-rTW │ │ └── strings.xml │ └── values │ │ └── strings.xml ├── src │ └── main │ │ └── java │ │ └── com │ │ └── topjohnwu │ │ └── magisk │ │ ├── ClassLoaders.java │ │ ├── DelegateApplication.java │ │ ├── DelegateComponentFactory.java │ │ ├── DownloadActivity.java │ │ ├── InjectAPK.java │ │ ├── dummy │ │ ├── DummyProvider.java │ │ └── DummyReceiver.java │ │ └── net │ │ ├── BadRequest.java │ │ ├── ErrorHandler.java │ │ ├── Networking.java │ │ ├── Request.java │ │ └── ResponseListener.java └── template │ ├── AndroidManifest.xml │ └── Mapping.java └── tools ├── elf-cleaner.exe ├── futility ├── keys ├── kernel.keyblock ├── kernel_data_key.vbprivk ├── testkey.pk8 ├── testkey.x509.pem ├── verity.pk8 └── verity.x509.pem └── ndk-bins ├── 16 ├── arm │ ├── crtbegin_dynamic.o │ ├── crtbegin_so.o │ ├── crtbegin_static.o │ ├── crtend_android.o │ ├── crtend_so.o │ ├── libc.a │ ├── libm.a │ └── libstdc++.a └── i686 │ ├── crtbegin_dynamic.o │ ├── crtbegin_so.o │ ├── crtbegin_static.o │ ├── crtend_android.o │ ├── crtend_so.o │ ├── libc.a │ ├── libm.a │ ├── libstdc++.a │ └── libz.a ├── 21 ├── aarch64 │ ├── crtbegin_dynamic.o │ ├── crtbegin_so.o │ ├── crtbegin_static.o │ ├── crtend_android.o │ ├── crtend_so.o │ ├── libc.a │ ├── libm.a │ ├── libstdc++.a │ └── libz.a ├── arm │ ├── crtbegin_dynamic.o │ ├── crtbegin_so.o │ ├── crtbegin_static.o │ ├── crtend_android.o │ ├── crtend_so.o │ ├── libc.a │ ├── libm.a │ ├── libstdc++.a │ └── libz.a ├── i686 │ ├── crtbegin_dynamic.o │ ├── crtbegin_so.o │ ├── crtbegin_static.o │ ├── crtend_android.o │ ├── crtend_so.o │ ├── libc.a │ ├── libm.a │ ├── libstdc++.a │ └── libz.a └── x86_64 │ ├── crtbegin_dynamic.o │ ├── crtbegin_so.o │ ├── crtbegin_static.o │ ├── crtend_android.o │ ├── crtend_so.o │ ├── libc.a │ ├── libm.a │ ├── libstdc++.a │ └── libz.a └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text eol=lf 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | # *.c text 7 | # *.h text 8 | 9 | # Declare files that will always have CRLF line endings on checkout. 10 | *.cmd text eol=crlf 11 | *.bat text eol=crlf 12 | 13 | # Denote all files that are truly binary and should not be modified. 14 | tools/** binary 15 | *.jar binary 16 | *.exe binary 17 | *.apk binary 18 | *.png binary 19 | *.jpg binary 20 | *.ttf binary 21 | 22 | # Help GitHub detect languages 23 | native/jni/external/** linguist-vendored 24 | native/jni/systemproperties/** linguist-language=C++ 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: XDA Community Support 4 | url: https://forum.xda-developers.com/f/magisk.5903/ 5 | about: Please ask and answer questions here. 6 | 7 | -------------------------------------------------------------------------------- /.github/ccache.sh: -------------------------------------------------------------------------------- 1 | OS=$(uname) 2 | CCACHE_VER=4.4 3 | 4 | case $OS in 5 | Darwin ) 6 | brew install ccache 7 | ln -s $(which ccache) ./ccache 8 | ;; 9 | Linux ) 10 | sudo apt-get install -y ccache 11 | ln -s $(which ccache) ./ccache 12 | ;; 13 | * ) 14 | curl -OL https://github.com/ccache/ccache/releases/download/v${CCACHE_VER}/ccache-${CCACHE_VER}-windows-64.zip 15 | unzip -j ccache-*-windows-64.zip '*/ccache.exe' 16 | ;; 17 | esac 18 | mkdir ./.ccache 19 | ./ccache -o compiler_check='%compiler% -dumpmachine; %compiler% -dumpversion' 20 | -------------------------------------------------------------------------------- /.github/workflows/issues.yml: -------------------------------------------------------------------------------- 1 | name: Check Issues 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | jobs: 7 | check: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Check out 11 | uses: actions/checkout@v2 12 | - name: Read latest version code 13 | run: | 14 | ver=$(sed -n 's/^magisk.versionCode=//p' gradle.properties) 15 | echo MAGISK_VERSION_CODE=$ver >> $GITHUB_ENV 16 | - if: contains(github.event.issue.body, format('Magisk version code{0} ', ':')) != true 17 | id: close 18 | name: Close Issue(template) 19 | uses: peter-evans/close-issue@v1 20 | with: 21 | comment: This issue is being automatically closed because it does not follow the issue template. 22 | - if: steps.close.conclusion == 'skipped' && contains(github.event.issue.body, format('Magisk version code{0} {1}', ':', env.MAGISK_VERSION_CODE)) != true 23 | name: Close Issue(latest canary) 24 | uses: peter-evans/close-issue@v1 25 | with: 26 | comment: This issue is being automatically closed because latest canary Magisk version code is ${{ env.MAGISK_VERSION_CODE }}. 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | *.zip 3 | *.jks 4 | *.apk 5 | /config.prop 6 | /update.sh 7 | /dict.txt 8 | 9 | # Built binaries 10 | native/out 11 | 12 | # Android Studio / Gradle 13 | *.iml 14 | .gradle 15 | /local.properties 16 | /.idea 17 | /build 18 | /captures 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea/ 5 | /build 6 | app/release 7 | *.hprof 8 | .externalNativeBuild/ 9 | *.apk 10 | src/main/assets 11 | src/main/jniLibs 12 | src/main/resources 13 | -------------------------------------------------------------------------------- /app/shared/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/shared/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | } 4 | 5 | setupCommon() 6 | 7 | android { 8 | defaultConfig { 9 | consumerProguardFiles("proguard-rules.pro") 10 | } 11 | } 12 | 13 | dependencies { 14 | api("io.michaelrocks:paranoid-core:0.3.5") 15 | } 16 | -------------------------------------------------------------------------------- /app/shared/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/shared/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 18 | 19 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/shared/src/main/java/com/topjohnwu/magisk/ProviderInstaller.java: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk; 2 | 3 | import android.content.Context; 4 | 5 | import io.michaelrocks.paranoid.Obfuscate; 6 | 7 | @Obfuscate 8 | public class ProviderInstaller { 9 | 10 | public static boolean install(Context context) { 11 | try { 12 | // Try installing new SSL provider from Google Play Service 13 | Context gms = context.createPackageContext("com.google.android.gms", 14 | Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); 15 | gms.getClassLoader() 16 | .loadClass("com.google.android.gms.common.security.ProviderInstallerImpl") 17 | .getMethod("insertProvider", Context.class) 18 | .invoke(null, gms); 19 | } catch (Exception e) { 20 | return false; 21 | } 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/shared/src/main/java/com/topjohnwu/magisk/utils/CompoundEnumeration.java: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.utils; 2 | 3 | import java.util.Enumeration; 4 | import java.util.NoSuchElementException; 5 | 6 | public class CompoundEnumeration implements Enumeration { 7 | private Enumeration[] enums; 8 | private int index = 0; 9 | 10 | @SafeVarargs 11 | public CompoundEnumeration(Enumeration ...enums) { 12 | this.enums = enums; 13 | } 14 | 15 | private boolean next() { 16 | while (index < enums.length) { 17 | if (enums[index] != null && enums[index].hasMoreElements()) { 18 | return true; 19 | } 20 | index++; 21 | } 22 | return false; 23 | } 24 | 25 | public boolean hasMoreElements() { 26 | return next(); 27 | } 28 | 29 | public E nextElement() { 30 | if (!next()) { 31 | throw new NoSuchElementException(); 32 | } 33 | return enums[index].nextElement(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/arch/BaseUIComponent.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.arch 2 | 3 | import android.view.View 4 | import androidx.lifecycle.LifecycleOwner 5 | 6 | interface BaseUIComponent : LifecycleOwner { 7 | 8 | val viewRoot: View 9 | val viewModel: VM 10 | 11 | fun startObserveEvents() { 12 | viewModel.viewEvents.observe(this) { 13 | onEventDispatched(it) 14 | } 15 | } 16 | 17 | /** 18 | * Called for all [ViewEvent]s published by associated viewModel. 19 | */ 20 | fun onEventDispatched(event: ViewEvent) {} 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/arch/Queryable.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.arch 2 | 3 | import android.os.Handler 4 | import androidx.core.os.postDelayed 5 | import com.topjohnwu.superuser.internal.UiThreadHandler 6 | 7 | interface Queryable { 8 | 9 | val queryDelay: Long 10 | val queryHandler: Handler get() = UiThreadHandler.handler 11 | 12 | fun submitQuery() { 13 | queryHandler.postDelayed(queryDelay) { query() } 14 | } 15 | 16 | fun query() 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/arch/ViewEvent.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.arch 2 | 3 | import android.content.Context 4 | import kotlinx.coroutines.CoroutineScope 5 | 6 | /** 7 | * Class for passing events from ViewModels to Activities/Fragments 8 | * (see https://medium.com/google-developers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150) 9 | */ 10 | abstract class ViewEvent 11 | 12 | abstract class ViewEventWithScope: ViewEvent() { 13 | lateinit var scope: CoroutineScope 14 | } 15 | 16 | interface ContextExecutor { 17 | operator fun invoke(context: Context) 18 | } 19 | 20 | interface ActivityExecutor { 21 | operator fun invoke(activity: BaseUIActivity<*, *>) 22 | } 23 | 24 | interface FragmentExecutor { 25 | operator fun invoke(fragment: BaseUIFragment<*, *>) 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/base/BaseReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.base 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.ContextWrapper 6 | import android.content.Intent 7 | import com.topjohnwu.magisk.core.wrap 8 | 9 | abstract class BaseReceiver : BroadcastReceiver() { 10 | 11 | final override fun onReceive(context: Context, intent: Intent?) { 12 | onReceive(context.wrap() as ContextWrapper, intent) 13 | } 14 | 15 | abstract fun onReceive(context: ContextWrapper, intent: Intent?) 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/base/BaseService.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.base 2 | 3 | import android.app.Service 4 | import android.content.Context 5 | import com.topjohnwu.magisk.core.wrap 6 | 7 | abstract class BaseService : Service() { 8 | override fun attachBaseContext(base: Context) { 9 | super.attachBaseContext(base.wrap()) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/base/PermissionRequestBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.base 2 | 3 | typealias SimpleCallback = () -> Unit 4 | typealias PermissionRationaleCallback = (List) -> Unit 5 | 6 | class PermissionRequestBuilder { 7 | 8 | private var onSuccessCallback: SimpleCallback = {} 9 | private var onFailureCallback: SimpleCallback = {} 10 | private var onShowRationaleCallback: PermissionRationaleCallback = {} 11 | 12 | fun onSuccess(callback: SimpleCallback) { 13 | onSuccessCallback = callback 14 | } 15 | 16 | fun onFailure(callback: SimpleCallback) { 17 | onFailureCallback = callback 18 | } 19 | 20 | fun onShowRationale(callback: PermissionRationaleCallback) { 21 | onShowRationaleCallback = callback 22 | } 23 | 24 | fun build(): PermissionRequest { 25 | return PermissionRequest(onSuccessCallback, onFailureCallback, onShowRationaleCallback) 26 | } 27 | 28 | } 29 | 30 | class PermissionRequest( 31 | private val onSuccessCallback: SimpleCallback, 32 | private val onFailureCallback: SimpleCallback, 33 | private val onShowRationaleCallback: PermissionRationaleCallback 34 | ) { 35 | 36 | fun onSuccess() = onSuccessCallback() 37 | fun onFailure() = onFailureCallback() 38 | fun onShowRationale(permissions: List) = onShowRationaleCallback(permissions) 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/magiskdb/BaseDao.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.magiskdb 2 | 3 | import androidx.annotation.StringDef 4 | 5 | abstract class BaseDao { 6 | 7 | object Table { 8 | const val POLICY = "policies" 9 | const val LOG = "logs" 10 | const val SETTINGS = "settings" 11 | const val STRINGS = "strings" 12 | } 13 | 14 | @StringDef(Table.POLICY, Table.LOG, Table.SETTINGS, Table.STRINGS) 15 | @Retention(AnnotationRetention.SOURCE) 16 | annotation class TableStrict 17 | 18 | @TableStrict 19 | abstract val table: String 20 | 21 | inline fun buildQuery(builder: Builder.() -> Unit = {}) = 22 | Builder::class.java.newInstance() 23 | .apply { table = this@BaseDao.table } 24 | .apply(builder) 25 | .toString() 26 | .let { Query(it) } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/magiskdb/SettingsDao.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.magiskdb 2 | 3 | class SettingsDao : BaseDao() { 4 | 5 | override val table = Table.SETTINGS 6 | 7 | suspend fun delete(key: String) = buildQuery { 8 | condition { equals("key", key) } 9 | }.commit() 10 | 11 | suspend fun put(key: String, value: Int) = buildQuery { 12 | values("key" to key, "value" to value) 13 | }.commit() 14 | 15 | suspend fun fetch(key: String, default: Int = -1) = buildQuery { 16 | fields("value") 17 | condition { equals("key", key) } 18 | }.query { 19 | it["value"] 20 | }.firstOrNull() ?: default 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.model 2 | 3 | import android.os.Parcelable 4 | import com.squareup.moshi.JsonClass 5 | import kotlinx.parcelize.Parcelize 6 | 7 | @JsonClass(generateAdapter = true) 8 | data class UpdateInfo( 9 | val magisk: MagiskJson = MagiskJson(), 10 | val stub: StubJson = StubJson() 11 | ) 12 | 13 | @Parcelize 14 | @JsonClass(generateAdapter = true) 15 | data class MagiskJson( 16 | val version: String = "", 17 | val versionCode: Int = -1, 18 | val link: String = "", 19 | val note: String = "" 20 | ) : Parcelable 21 | 22 | @Parcelize 23 | @JsonClass(generateAdapter = true) 24 | data class StubJson( 25 | val versionCode: Int = -1, 26 | val link: String = "" 27 | ) : Parcelable 28 | 29 | @JsonClass(generateAdapter = true) 30 | data class ModuleJson( 31 | val id: String, 32 | val last_update: Long, 33 | val prop_url: String, 34 | val zip_url: String, 35 | val notes_url: String 36 | ) 37 | 38 | @JsonClass(generateAdapter = true) 39 | data class RepoJson( 40 | val name: String, 41 | val last_update: Long, 42 | val modules: List 43 | ) 44 | 45 | @JsonClass(generateAdapter = true) 46 | data class CommitInfo( 47 | val sha: String 48 | ) 49 | 50 | @JsonClass(generateAdapter = true) 51 | data class BranchInfo( 52 | val commit: CommitInfo 53 | ) 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/model/su/SuLog.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.model.su 2 | 3 | import androidx.room.Entity 4 | import androidx.room.PrimaryKey 5 | import androidx.room.TypeConverter 6 | import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW 7 | import java.time.OffsetDateTime 8 | import java.time.format.DateTimeFormatter 9 | 10 | @Entity(tableName = "logs") 11 | data class SuLog( 12 | val fromUid: Int, 13 | val toUid: Int, 14 | val fromPid: Int, 15 | val packageName: String, 16 | val appName: String, 17 | val command: String, 18 | val action: Boolean, 19 | val time: OffsetDateTime = OffsetDateTime.now() 20 | ) { 21 | @PrimaryKey(autoGenerate = true) 22 | var id: Int = 0 23 | } 24 | 25 | class Converters { 26 | private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME 27 | 28 | @TypeConverter 29 | fun toOffsetDateTime(value: String?) = value?.let { 30 | formatter.parse(it, OffsetDateTime::from) 31 | } 32 | 33 | @TypeConverter 34 | fun fromOffsetDateTime(date: OffsetDateTime?) = date?.format(formatter) 35 | } 36 | 37 | fun SuPolicy.toLog( 38 | toUid: Int, 39 | fromPid: Int, 40 | command: String 41 | ) = SuLog(uid, toUid, fromPid, packageName, appName, command, policy == ALLOW) 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/utils/IODispatcherExecutor.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.utils 2 | 3 | import kotlinx.coroutines.* 4 | import java.util.concurrent.* 5 | 6 | class IODispatcherExecutor : AbstractExecutorService() { 7 | 8 | private val job = SupervisorJob().apply { invokeOnCompletion { future.run() } } 9 | private val scope = CoroutineScope(job + Dispatchers.IO) 10 | private val future = FutureTask(Callable { true }) 11 | 12 | override fun execute(command: Runnable) { 13 | scope.launch { 14 | command.run() 15 | } 16 | } 17 | 18 | override fun shutdown() = job.cancel() 19 | 20 | override fun shutdownNow(): List { 21 | job.cancel() 22 | return emptyList() 23 | } 24 | 25 | override fun isShutdown() = job.isCancelled 26 | 27 | override fun isTerminated() = job.isCancelled && job.isCompleted 28 | 29 | override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean { 30 | return try { 31 | future.get(timeout, unit) 32 | } catch (e: TimeoutException) { 33 | false 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/utils/ProgressInputStream.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.utils 2 | 3 | import java.io.FilterInputStream 4 | import java.io.InputStream 5 | 6 | class ProgressInputStream( 7 | base: InputStream, 8 | val progressEmitter: (Long) -> Unit = {} 9 | ) : FilterInputStream(base) { 10 | 11 | private var bytesRead = 0L 12 | private var lastUpdate = 0L 13 | 14 | private fun emitProgress() { 15 | val cur = System.currentTimeMillis() 16 | if (cur - lastUpdate > 1000) { 17 | lastUpdate = cur 18 | progressEmitter(bytesRead) 19 | } 20 | } 21 | 22 | override fun read(): Int { 23 | val b = read() 24 | if (b >= 0) { 25 | bytesRead++ 26 | emitProgress() 27 | } 28 | return b 29 | } 30 | 31 | override fun read(b: ByteArray): Int { 32 | return read(b, 0, b.size) 33 | } 34 | 35 | override fun read(b: ByteArray, off: Int, len: Int): Int { 36 | val sz = super.read(b, off, len) 37 | if (sz > 0) { 38 | bytesRead += sz 39 | emitProgress() 40 | } 41 | return sz 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/core/utils/net/NetworkObserver.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.core.utils.net 2 | 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | import android.os.Build 6 | import androidx.core.content.getSystemService 7 | 8 | typealias ConnectionCallback = (Boolean) -> Unit 9 | 10 | abstract class NetworkObserver( 11 | context: Context, 12 | protected val callback: ConnectionCallback 13 | ) { 14 | 15 | protected val app: Context = context.applicationContext 16 | protected val manager = context.getSystemService()!! 17 | 18 | protected abstract fun stopObserving() 19 | protected abstract fun getCurrentState() 20 | 21 | companion object { 22 | fun observe(context: Context, callback: ConnectionCallback): NetworkObserver { 23 | val observer: NetworkObserver = if (Build.VERSION.SDK_INT >= 23) 24 | MarshmallowNetworkObserver(context, callback) 25 | else LollipopNetworkObserver(context, callback) 26 | return observer.apply { getCurrentState() } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/database/SuLogDao.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.database 2 | 3 | import androidx.room.* 4 | import com.topjohnwu.magisk.core.model.su.Converters 5 | import com.topjohnwu.magisk.core.model.su.SuLog 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.withContext 8 | import java.time.OffsetDateTime 9 | 10 | @Database(version = 2, entities = [SuLog::class], exportSchema = false) 11 | @TypeConverters(Converters::class) 12 | abstract class SuLogDatabase : RoomDatabase() { 13 | 14 | abstract fun suLogDao(): SuLogDao 15 | } 16 | 17 | @Dao 18 | abstract class SuLogDao(private val db: SuLogDatabase) { 19 | 20 | private val twoWeeksAgo = OffsetDateTime.now().minusWeeks(2) 21 | 22 | suspend fun deleteAll() = withContext(Dispatchers.IO) { db.clearAllTables() } 23 | 24 | suspend fun fetchAll(): MutableList { 25 | deleteOutdated() 26 | return fetch() 27 | } 28 | 29 | @Query("SELECT * FROM logs ORDER BY time DESC") 30 | protected abstract suspend fun fetch(): MutableList 31 | 32 | @Query("DELETE FROM logs WHERE datetime(time) < datetime(:timeout)") 33 | protected abstract suspend fun deleteOutdated(timeout: OffsetDateTime = twoWeeksAgo) 34 | 35 | @Insert 36 | abstract suspend fun insert(log: SuLog) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/BooleanProperty.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import androidx.core.content.edit 4 | import com.topjohnwu.magisk.ktx.trimEmptyToNull 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class BooleanProperty( 9 | private val name: String, 10 | private val default: Boolean, 11 | private val commit: Boolean 12 | ) : Property(), ReadWriteProperty { 13 | 14 | override operator fun getValue( 15 | thisRef: PreferenceModel, 16 | property: KProperty<*> 17 | ): Boolean { 18 | val prefName = name.trimEmptyToNull() ?: property.name 19 | return thisRef.prefs.get(prefName, default) 20 | } 21 | 22 | override operator fun setValue( 23 | thisRef: PreferenceModel, 24 | property: KProperty<*>, 25 | value: Boolean 26 | ) { 27 | val prefName = name.trimEmptyToNull() ?: property.name 28 | thisRef.prefs.edit(commit) { put(prefName, value) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/FloatProperty.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import androidx.core.content.edit 4 | import com.topjohnwu.magisk.ktx.trimEmptyToNull 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class FloatProperty( 9 | private val name: String, 10 | private val default: Float, 11 | private val commit: Boolean 12 | ) : Property(), ReadWriteProperty { 13 | 14 | override operator fun getValue( 15 | thisRef: PreferenceModel, 16 | property: KProperty<*> 17 | ): Float { 18 | val prefName = name.trimEmptyToNull() ?: property.name 19 | return thisRef.prefs.get(prefName, default) 20 | } 21 | 22 | override operator fun setValue( 23 | thisRef: PreferenceModel, 24 | property: KProperty<*>, 25 | value: Float 26 | ) { 27 | val prefName = name.trimEmptyToNull() ?: property.name 28 | thisRef.prefs.edit(commit) { put(prefName, value) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/IntProperty.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import androidx.core.content.edit 4 | import com.topjohnwu.magisk.ktx.trimEmptyToNull 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class IntProperty( 9 | private val name: String, 10 | private val default: Int, 11 | private val commit: Boolean 12 | ) : Property(), ReadWriteProperty { 13 | 14 | override operator fun getValue( 15 | thisRef: PreferenceModel, 16 | property: KProperty<*> 17 | ): Int { 18 | val prefName = name.trimEmptyToNull() ?: property.name 19 | return thisRef.prefs.get(prefName, default) 20 | } 21 | 22 | override operator fun setValue( 23 | thisRef: PreferenceModel, 24 | property: KProperty<*>, 25 | value: Int 26 | ) { 27 | val prefName = name.trimEmptyToNull() ?: property.name 28 | thisRef.prefs.edit(commit) { put(prefName, value) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/LongProperty.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import androidx.core.content.edit 4 | import com.topjohnwu.magisk.ktx.trimEmptyToNull 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class LongProperty( 9 | private val name: String, 10 | private val default: Long, 11 | private val commit: Boolean 12 | ) : Property(), ReadWriteProperty { 13 | 14 | override operator fun getValue( 15 | thisRef: PreferenceModel, 16 | property: KProperty<*> 17 | ): Long { 18 | val prefName = name.trimEmptyToNull() ?: property.name 19 | return thisRef.prefs.get(prefName, default) 20 | } 21 | 22 | override operator fun setValue( 23 | thisRef: PreferenceModel, 24 | property: KProperty<*>, 25 | value: Long 26 | ) { 27 | val prefName = name.trimEmptyToNull() ?: property.name 28 | thisRef.prefs.edit(commit) { put(prefName, value) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/Property.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import android.content.SharedPreferences 4 | 5 | abstract class Property { 6 | 7 | fun SharedPreferences.Editor.put(name: String, value: Boolean) = putBoolean(name, value) 8 | fun SharedPreferences.Editor.put(name: String, value: Float) = putFloat(name, value) 9 | fun SharedPreferences.Editor.put(name: String, value: Int) = putInt(name, value) 10 | fun SharedPreferences.Editor.put(name: String, value: Long) = putLong(name, value) 11 | fun SharedPreferences.Editor.put(name: String, value: String) = putString(name, value) 12 | fun SharedPreferences.Editor.put(name: String, value: Set) = putStringSet(name, value) 13 | 14 | fun SharedPreferences.get(name: String, value: Boolean) = getBoolean(name, value) 15 | fun SharedPreferences.get(name: String, value: Float) = getFloat(name, value) 16 | fun SharedPreferences.get(name: String, value: Int) = getInt(name, value) 17 | fun SharedPreferences.get(name: String, value: Long) = getLong(name, value) 18 | fun SharedPreferences.get(name: String, value: String) = getString(name, value) ?: value 19 | fun SharedPreferences.get(name: String, value: Set) = getStringSet(name, value) ?: value 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/StringProperty.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import androidx.core.content.edit 4 | import com.topjohnwu.magisk.ktx.trimEmptyToNull 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class StringProperty( 9 | private val name: String, 10 | private val default: String, 11 | private val commit: Boolean 12 | ) : Property(), ReadWriteProperty { 13 | 14 | override operator fun getValue( 15 | thisRef: PreferenceModel, 16 | property: KProperty<*> 17 | ): String { 18 | val prefName = name.trimEmptyToNull() ?: property.name 19 | return thisRef.prefs.get(prefName, default) 20 | } 21 | 22 | override operator fun setValue( 23 | thisRef: PreferenceModel, 24 | property: KProperty<*>, 25 | value: String 26 | ) { 27 | val prefName = name.trimEmptyToNull() ?: property.name 28 | thisRef.prefs.edit(commit) { put(prefName, value) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/data/preference/StringSetProperty.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.data.preference 2 | 3 | import androidx.core.content.edit 4 | import com.topjohnwu.magisk.ktx.trimEmptyToNull 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class StringSetProperty( 9 | private val name: String, 10 | private val default: Set, 11 | private val commit: Boolean 12 | ) : Property(), ReadWriteProperty> { 13 | 14 | override operator fun getValue( 15 | thisRef: PreferenceModel, 16 | property: KProperty<*> 17 | ): Set { 18 | val prefName = name.trimEmptyToNull() ?: property.name 19 | return thisRef.prefs.get(prefName, default) 20 | } 21 | 22 | override operator fun setValue( 23 | thisRef: PreferenceModel, 24 | property: KProperty<*>, 25 | value: Set 26 | ) { 27 | val prefName = name.trimEmptyToNull() ?: property.name 28 | thisRef.prefs.edit(commit) { put(prefName, value) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/databinding/BindingBoundAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.databinding 2 | 3 | import androidx.databinding.ViewDataBinding 4 | import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter 5 | 6 | open class BindingBoundAdapter : BindingRecyclerViewAdapter() { 7 | 8 | override fun onBindBinding(binding: ViewDataBinding, variableId: Int, layoutRes: Int, position: Int, item: RvItem) { 9 | super.onBindBinding(binding, variableId, layoutRes, position, item) 10 | 11 | item.onBindingBound(binding) 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/databinding/Helpers.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.databinding 2 | 3 | import androidx.databinding.ViewDataBinding 4 | import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter 5 | import me.tatarka.bindingcollectionadapter2.ItemBinding 6 | import me.tatarka.bindingcollectionadapter2.OnItemBind 7 | 8 | fun diffListOf() = 9 | DiffObservableList(DiffRvItem.callback()) 10 | 11 | fun diffListOf(newItems: List) = 12 | DiffObservableList(DiffRvItem.callback()).also { it.update(newItems) } 13 | 14 | fun filterableListOf() = 15 | FilterableDiffObservableList(DiffRvItem.callback()) 16 | 17 | fun adapterOf() = object : BindingRecyclerViewAdapter() { 18 | override fun onBindBinding( 19 | binding: ViewDataBinding, 20 | variableId: Int, 21 | layoutRes: Int, 22 | position: Int, 23 | item: T 24 | ) { 25 | super.onBindBinding(binding, variableId, layoutRes, position, item) 26 | item.onBindingBound(binding) 27 | } 28 | } 29 | 30 | inline fun itemBindingOf( 31 | crossinline body: (ItemBinding<*>) -> Unit = {} 32 | ) = OnItemBind { itemBinding, _, item -> 33 | item.bind(itemBinding) 34 | body(itemBinding) 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/databinding/RvBindingAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.databinding 2 | 3 | import androidx.databinding.ViewDataBinding 4 | import androidx.recyclerview.widget.RecyclerView 5 | import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter 6 | 7 | class RvBindingAdapter : BindingRecyclerViewAdapter() { 8 | 9 | private var recyclerView: RecyclerView? = null 10 | 11 | override fun onBindBinding( 12 | binding: ViewDataBinding, 13 | variableId: Int, 14 | layoutRes: Int, 15 | position: Int, 16 | item: T 17 | ) { 18 | super.onBindBinding(binding, variableId, layoutRes, position, item) 19 | 20 | when (item) { 21 | is LenientRvItem -> { 22 | val recycler = recyclerView ?: return 23 | item.onBindingBound(binding) 24 | item.onBindingBound(binding, recycler) 25 | } 26 | else -> item.onBindingBound(binding) 27 | } 28 | } 29 | 30 | override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { 31 | super.onAttachedToRecyclerView(recyclerView) 32 | this.recyclerView = recyclerView 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/events/OpenInappLinkEvent.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.events 2 | 3 | import android.content.Context 4 | import android.content.res.Resources 5 | import android.util.TypedValue 6 | import androidx.annotation.AttrRes 7 | import androidx.browser.customtabs.CustomTabsIntent 8 | import androidx.core.net.toUri 9 | import com.topjohnwu.magisk.R 10 | import com.topjohnwu.magisk.arch.ContextExecutor 11 | import com.topjohnwu.magisk.arch.ViewEvent 12 | 13 | data class OpenInappLinkEvent( 14 | private val link: String 15 | ) : ViewEvent(), ContextExecutor { 16 | 17 | // todo find app that can open the link and as a fallback open custom tabs! it shouldn't be the default 18 | override fun invoke(context: Context) = CustomTabsIntent.Builder() 19 | .setShowTitle(true) 20 | .setToolbarColor(context.themedColor(R.attr.colorSurface)) 21 | .enableUrlBarHiding() 22 | .build() 23 | .launchUrl(context, link.toUri()) 24 | 25 | private fun Context.themedColor(@AttrRes attribute: Int) = theme 26 | .resolveAttribute(attribute).data 27 | 28 | private fun Resources.Theme.resolveAttribute( 29 | @AttrRes attribute: Int, 30 | resolveRefs: Boolean = true 31 | ) = TypedValue().also { resolveAttribute(attribute, it, resolveRefs) } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/events/dialog/BiometricEvent.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.events.dialog 2 | 3 | import com.topjohnwu.magisk.arch.ActivityExecutor 4 | import com.topjohnwu.magisk.arch.BaseUIActivity 5 | import com.topjohnwu.magisk.arch.ViewEvent 6 | import com.topjohnwu.magisk.core.utils.BiometricHelper 7 | 8 | class BiometricEvent( 9 | builder: Builder.() -> Unit 10 | ) : ViewEvent(), ActivityExecutor { 11 | 12 | private var listenerOnFailure: GenericDialogListener = {} 13 | private var listenerOnSuccess: GenericDialogListener = {} 14 | 15 | init { 16 | builder(Builder()) 17 | } 18 | 19 | override fun invoke(activity: BaseUIActivity<*, *>) { 20 | BiometricHelper.authenticate( 21 | activity, 22 | onError = listenerOnFailure, 23 | onSuccess = listenerOnSuccess 24 | ) 25 | } 26 | 27 | inner class Builder internal constructor() { 28 | 29 | fun onFailure(listener: GenericDialogListener) { 30 | listenerOnFailure = listener 31 | } 32 | 33 | fun onSuccess(listener: GenericDialogListener) { 34 | listenerOnSuccess = listener 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/events/dialog/DialogEvent.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.events.dialog 2 | 3 | import com.topjohnwu.magisk.arch.ActivityExecutor 4 | import com.topjohnwu.magisk.arch.BaseUIActivity 5 | import com.topjohnwu.magisk.arch.ViewEvent 6 | import com.topjohnwu.magisk.view.MagiskDialog 7 | 8 | abstract class DialogEvent : ViewEvent(), ActivityExecutor { 9 | 10 | protected lateinit var dialog: MagiskDialog 11 | 12 | override fun invoke(activity: BaseUIActivity<*, *>) { 13 | dialog = MagiskDialog(activity) 14 | .apply { setOwnerActivity(activity) } 15 | .apply(this::build).reveal() 16 | } 17 | 18 | abstract fun build(dialog: MagiskDialog) 19 | 20 | } 21 | 22 | typealias GenericDialogListener = () -> Unit 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/events/dialog/ManagerInstallDialog.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.events.dialog 2 | 3 | import com.topjohnwu.magisk.R 4 | import com.topjohnwu.magisk.core.Info 5 | import com.topjohnwu.magisk.core.download.DownloadService 6 | import com.topjohnwu.magisk.core.download.Subject 7 | import com.topjohnwu.magisk.di.ServiceLocator 8 | import com.topjohnwu.magisk.view.MagiskDialog 9 | 10 | class ManagerInstallDialog : MarkDownDialog() { 11 | 12 | private val svc get() = ServiceLocator.networkService 13 | 14 | override suspend fun getMarkdownText(): String { 15 | return svc.fetchString(Info.remote.magisk.note) 16 | } 17 | 18 | override fun build(dialog: MagiskDialog) { 19 | super.build(dialog) 20 | with(dialog) { 21 | setCancelable(true) 22 | applyButton(MagiskDialog.ButtonType.POSITIVE) { 23 | titleRes = R.string.install 24 | onClick { DownloadService.start(context, Subject.Manager()) } 25 | } 26 | applyButton(MagiskDialog.ButtonType.NEGATIVE) { 27 | titleRes = android.R.string.cancel 28 | } 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/events/dialog/SecondSlotWarningDialog.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.events.dialog 2 | 3 | import com.topjohnwu.magisk.R 4 | import com.topjohnwu.magisk.view.MagiskDialog 5 | 6 | class SecondSlotWarningDialog : DialogEvent() { 7 | 8 | override fun build(dialog: MagiskDialog) { 9 | dialog.applyTitle(android.R.string.dialog_alert_title) 10 | .applyMessage(R.string.install_inactive_slot_msg) 11 | .applyButton(MagiskDialog.ButtonType.POSITIVE) { 12 | titleRes = android.R.string.ok 13 | } 14 | .cancellable(true) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/events/dialog/SuperuserRevokeDialog.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.events.dialog 2 | 3 | import com.topjohnwu.magisk.R 4 | import com.topjohnwu.magisk.view.MagiskDialog 5 | 6 | class SuperuserRevokeDialog( 7 | builder: Builder.() -> Unit 8 | ) : DialogEvent() { 9 | 10 | private val callbacks = Builder().apply(builder) 11 | 12 | override fun build(dialog: MagiskDialog) { 13 | dialog.applyTitle(R.string.su_revoke_title) 14 | .applyMessage(R.string.su_revoke_msg, callbacks.appName) 15 | .applyButton(MagiskDialog.ButtonType.POSITIVE) { 16 | titleRes = android.R.string.ok 17 | onClick { callbacks.listenerOnSuccess() } 18 | } 19 | .applyButton(MagiskDialog.ButtonType.NEGATIVE) { 20 | titleRes = android.R.string.cancel 21 | } 22 | } 23 | 24 | inner class Builder internal constructor() { 25 | var appName: String = "" 26 | 27 | internal var listenerOnSuccess: GenericDialogListener = {} 28 | 29 | fun onSuccess(listener: GenericDialogListener) { 30 | listenerOnSuccess = listener 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ktx/Dimens.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ktx 2 | 3 | import android.content.res.Resources 4 | import kotlin.math.ceil 5 | import kotlin.math.roundToInt 6 | 7 | fun Int.toDp(): Int = ceil(this / Resources.getSystem().displayMetrics.density).roundToInt() 8 | 9 | fun Int.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).roundToInt() 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ktx/XSU.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ktx 2 | 3 | import android.content.Context 4 | import com.topjohnwu.magisk.core.Config 5 | import com.topjohnwu.magisk.core.Const 6 | import com.topjohnwu.superuser.Shell 7 | import kotlinx.coroutines.Dispatchers 8 | import kotlinx.coroutines.withContext 9 | 10 | fun reboot(reason: String = if (Config.recovery) "recovery" else "") { 11 | Shell.su("/system/bin/svc power reboot $reason || /system/bin/reboot $reason").submit() 12 | } 13 | 14 | fun relaunchApp(context: Context) { 15 | val intent = context.packageManager.getLaunchIntentForPackage(context.packageName) ?: return 16 | val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString()) 17 | val cmd = intent.toCommand(args).joinToString(separator = " ") 18 | Shell.su("run_delay 1 \"$cmd\"").exec() 19 | Runtime.getRuntime().exit(0) 20 | } 21 | 22 | suspend fun Shell.Job.await() = withContext(Dispatchers.IO) { exec() } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/signing/ByteArrayStream.java: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.signing; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | public class ByteArrayStream extends ByteArrayOutputStream { 9 | 10 | public synchronized void readFrom(InputStream is) { 11 | readFrom(is, Integer.MAX_VALUE); 12 | } 13 | 14 | public synchronized void readFrom(InputStream is, int len) { 15 | int read; 16 | byte buffer[] = new byte[4096]; 17 | try { 18 | while ((read = is.read(buffer, 0, Math.min(len, buffer.length))) > 0) { 19 | write(buffer, 0, read); 20 | len -= read; 21 | } 22 | } catch (IOException e) { 23 | e.printStackTrace(); 24 | } 25 | } 26 | 27 | public ByteArrayInputStream getInputStream() { 28 | return new ByteArrayInputStream(buf, 0, count); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ui/flash/ConsoleItem.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ui.flash 2 | 3 | import android.view.View 4 | import android.widget.TextView 5 | import androidx.core.view.updateLayoutParams 6 | import androidx.databinding.ViewDataBinding 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.topjohnwu.magisk.R 9 | import com.topjohnwu.magisk.databinding.DiffRvItem 10 | import com.topjohnwu.magisk.databinding.LenientRvItem 11 | import com.topjohnwu.magisk.databinding.RvContainer 12 | import kotlin.math.max 13 | 14 | class ConsoleItem( 15 | override val item: String 16 | ) : DiffRvItem(), LenientRvItem, 17 | RvContainer { 18 | override val layoutRes = R.layout.item_console_md2 19 | 20 | private var parentWidth = -1 21 | 22 | override fun onBindingBound(binding: ViewDataBinding, recyclerView: RecyclerView) { 23 | if (parentWidth < 0) 24 | parentWidth = (recyclerView.parent as View).width 25 | 26 | val view = binding.root as TextView 27 | view.measure(0, 0) 28 | 29 | // We want our recyclerView at least as wide as screen 30 | val desiredWidth = max(view.measuredWidth, parentWidth) 31 | 32 | view.updateLayoutParams { width = desiredWidth } 33 | 34 | if (recyclerView.width < desiredWidth) { 35 | recyclerView.requestLayout() 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ui/log/LogRvItem.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ui.log 2 | 3 | import androidx.databinding.Bindable 4 | import com.topjohnwu.magisk.BR 5 | import com.topjohnwu.magisk.R 6 | import com.topjohnwu.magisk.core.model.su.SuLog 7 | import com.topjohnwu.magisk.core.utils.currentLocale 8 | import com.topjohnwu.magisk.databinding.ObservableDiffRvItem 9 | import com.topjohnwu.magisk.databinding.RvContainer 10 | import com.topjohnwu.magisk.databinding.set 11 | import java.time.format.DateTimeFormatter 12 | import java.time.format.FormatStyle 13 | 14 | class LogRvItem( 15 | override val item: SuLog 16 | ) : ObservableDiffRvItem(), RvContainer { 17 | 18 | companion object { 19 | val timeDateFormat = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL) 20 | .withLocale(currentLocale)!! 21 | } 22 | 23 | override val layoutRes = R.layout.item_log_access_md2 24 | 25 | val date: String = timeDateFormat.format(item.time.toZonedDateTime()) 26 | 27 | @get:Bindable 28 | var isTop = false 29 | set(value) = set(value, field, { field = it }, BR.top) 30 | 31 | @get:Bindable 32 | var isBottom = false 33 | set(value) = set(value, field, { field = it }, BR.bottom) 34 | 35 | override fun itemSameAs(other: LogRvItem) = item.appName == other.item.appName 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetyNetHelper.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ui.safetynet 2 | 3 | import android.content.Context 4 | 5 | interface SafetyNetHelper { 6 | 7 | val version: Int 8 | 9 | fun attest(context: Context, nonce: ByteArray, callback: Callback) 10 | 11 | interface Callback { 12 | fun onResponse(response: String?) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetFragment.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ui.safetynet 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import com.topjohnwu.magisk.R 8 | import com.topjohnwu.magisk.arch.BaseUIFragment 9 | import com.topjohnwu.magisk.databinding.FragmentSafetynetMd2Binding 10 | import com.topjohnwu.magisk.di.viewModel 11 | 12 | class SafetynetFragment : BaseUIFragment() { 13 | 14 | override val layoutRes = R.layout.fragment_safetynet_md2 15 | override val viewModel by viewModel() 16 | 17 | override fun onStart() { 18 | super.onStart() 19 | activity.setTitle(R.string.safetynet) 20 | } 21 | 22 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 23 | super.onCreateView(inflater, container, savedInstanceState) 24 | 25 | // Set barrier reference IDs in code, since resource IDs will be stripped in release mode 26 | binding.snetBarrier.referencedIds = intArrayOf(R.id.basic_text, R.id.cts_text) 27 | 28 | return binding.root 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/ui/theme/ThemeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.ui.theme 2 | 3 | import com.topjohnwu.magisk.arch.BaseViewModel 4 | import com.topjohnwu.magisk.events.RecreateEvent 5 | import com.topjohnwu.magisk.events.dialog.DarkThemeDialog 6 | import com.topjohnwu.magisk.view.TappableHeadlineItem 7 | 8 | class ThemeViewModel : BaseViewModel(), TappableHeadlineItem.Listener { 9 | 10 | val themeHeadline = TappableHeadlineItem.ThemeMode 11 | 12 | override fun onItemPressed(item: TappableHeadlineItem) = when (item) { 13 | is TappableHeadlineItem.ThemeMode -> darkModePressed() 14 | else -> Unit 15 | } 16 | 17 | fun saveTheme(theme: Theme) { 18 | theme.select() 19 | RecreateEvent().publish() 20 | } 21 | 22 | private fun darkModePressed() = DarkThemeDialog().publish() 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/utils/CachedValue.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.utils 2 | 3 | class CachedValue(private val factory: () -> T) : Lazy { 4 | 5 | private var _val : T? = null 6 | 7 | override val value: T 8 | get() { 9 | val local = _val 10 | return local ?: synchronized(this) { 11 | _val ?: factory().also { _val = it } 12 | } 13 | } 14 | 15 | override fun isInitialized() = _val != null 16 | 17 | fun invalidate() { 18 | synchronized(this) { 19 | _val = null 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/utils/HideableBehavior.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.utils 2 | 3 | import android.view.View 4 | 5 | interface HideableBehavior { 6 | 7 | fun setHidden(view: V, hide: Boolean, lockState: Boolean = false) 8 | 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/utils/TextHolder.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.utils 2 | 3 | import android.content.res.Resources 4 | import android.widget.TextView 5 | import androidx.databinding.BindingAdapter 6 | 7 | abstract class TextHolder { 8 | 9 | open val isEmpty: Boolean get() = false 10 | abstract fun getText(resources: Resources): CharSequence 11 | 12 | // --- 13 | 14 | class String( 15 | private val value: CharSequence 16 | ) : TextHolder() { 17 | 18 | override val isEmpty get() = value.isEmpty() 19 | override fun getText(resources: Resources) = value 20 | 21 | } 22 | 23 | class Resource( 24 | private val value: Int, 25 | private vararg val params: Any 26 | ) : TextHolder() { 27 | 28 | override val isEmpty get() = value == 0 29 | override fun getText(resources: Resources) = resources.getString(value, *params) 30 | 31 | } 32 | 33 | // --- 34 | 35 | companion object { 36 | val EMPTY = String("") 37 | } 38 | } 39 | 40 | fun Int.asText(vararg params: Any): TextHolder = TextHolder.Resource(this, *params) 41 | fun CharSequence.asText(): TextHolder = TextHolder.String(this) 42 | 43 | 44 | @BindingAdapter("android:text") 45 | fun TextView.setText(text: TextHolder) { 46 | this.text = text.getText(context.resources) 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/view/TappableHeadlineItem.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.view 2 | 3 | import com.topjohnwu.magisk.R 4 | import com.topjohnwu.magisk.databinding.DiffRvItem 5 | 6 | sealed class TappableHeadlineItem : DiffRvItem() { 7 | 8 | abstract val title: Int 9 | abstract val icon: Int 10 | 11 | override val layoutRes = R.layout.item_tappable_headline 12 | 13 | // --- listener 14 | 15 | interface Listener { 16 | 17 | fun onItemPressed(item: TappableHeadlineItem) 18 | 19 | } 20 | 21 | // --- objects 22 | 23 | object Hide : TappableHeadlineItem() { 24 | override val title = R.string.magiskhide 25 | override val icon = R.drawable.ic_hide_md2 26 | } 27 | 28 | object ThemeMode : TappableHeadlineItem() { 29 | override val title = R.string.settings_dark_mode_title 30 | override val icon = R.drawable.ic_day_night 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/topjohnwu/magisk/view/TextItem.kt: -------------------------------------------------------------------------------- 1 | package com.topjohnwu.magisk.view 2 | 3 | import com.topjohnwu.magisk.R 4 | import com.topjohnwu.magisk.databinding.DiffRvItem 5 | 6 | class TextItem(val text: Int) : DiffRvItem() { 7 | override val layoutRes = R.layout.item_text 8 | 9 | override fun contentSameAs(other: TextItem) = text == other.text 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fragment_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fragment_enter_pop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fragment_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fragment_exit_pop.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_error_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_menu_tint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_on_primary_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_primary_error_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_primary_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_secondary_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_state_primary_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_text_transient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderTyn/Magisk-Alpha/6f95730cf00f27e7b23112ab6702a4701bcdd2fe/app/src/main/res/drawable-nodpi/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v23/ic_splash_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v26/sc_extension.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v26/sc_magiskhide.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v26/sc_superuser.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_checkbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_divider_rounded_on_primary.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_line_bottom_rounded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_line_top_rounded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_selection_circle_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/divider_l1.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/divider_l_50.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back_md2.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bug_filled_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bug_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | 17 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bug_outlined_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle_checked_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle_unchecked_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_checkbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_compound_checkbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_day.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_day_night.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_md2.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_device.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_download_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_extension.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_folder_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forth_md2.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_github.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hide_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hide_select_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_filled_md2.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_outlined_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_install.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_logo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_magisk_delete.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_module_filled_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_module_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_module_outlined_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_module_storage_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_night.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_order_name.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_paint.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_patreon.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_data_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_safetynet_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_restart.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_safetynet_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_save_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_filled_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_show_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_superuser.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_superuser_filled_md2.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_superuser_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 12 | 13 | 17 | 18 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_superuser_outlined_md2.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_twitter.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_up_md2.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_update_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sc_extension.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sc_magiskhide.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sc_superuser.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_settings_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_console_md2.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_icon_link.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 15 | 16 | 17 | 18 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_list_single_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 17 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_module_download.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 17 |