├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── README.md ├── XposedInstaller.iml ├── app ├── Xposed-Disabler-Recovery.zip ├── Xposed-Installer-Recovery.zip ├── build.gradle ├── libs │ └── AndroidHiddenAPI.jar ├── lint.xml ├── proguard-project.txt ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ ├── XposedBridge.jar │ │ ├── arm │ │ │ ├── app_process_xposed_sdk15 │ │ │ ├── app_process_xposed_sdk16 │ │ │ ├── app_process_xposed_sdk19 │ │ │ └── busybox-xposed │ │ └── x86 │ │ │ ├── app_process_xposed_sdk15 │ │ │ ├── app_process_xposed_sdk16 │ │ │ ├── app_process_xposed_sdk19 │ │ │ └── busybox-xposed │ │ ├── java │ │ └── de │ │ │ └── robv │ │ │ └── android │ │ │ └── xposed │ │ │ └── installer │ │ │ ├── AboutActivity.java │ │ │ ├── DownloadDetailsActivity.java │ │ │ ├── DownloadDetailsFragment.java │ │ │ ├── DownloadDetailsSettingsFragment.java │ │ │ ├── DownloadDetailsVersionsFragment.java │ │ │ ├── DownloadFragment.java │ │ │ ├── LogsFragment.java │ │ │ ├── ModulesBookmark.java │ │ │ ├── ModulesFragment.java │ │ │ ├── SettingsActivity.java │ │ │ ├── SupportActivity.java │ │ │ ├── WelcomeActivity.java │ │ │ ├── XposedApp.java │ │ │ ├── XposedBaseActivity.java │ │ │ ├── installation │ │ │ ├── AdvancedInstallerFragment.java │ │ │ ├── BaseAdvancedInstaller.java │ │ │ ├── FlashCallback.java │ │ │ ├── FlashDirectly.java │ │ │ ├── FlashRecoveryAuto.java │ │ │ ├── Flashable.java │ │ │ ├── InstallationActivity.java │ │ │ └── StatusInstallerFragment.java │ │ │ ├── receivers │ │ │ ├── BootReceiver.java │ │ │ ├── DownloadReceiver.java │ │ │ └── PackageChangeReceiver.java │ │ │ ├── repo │ │ │ ├── Module.java │ │ │ ├── ModuleVersion.java │ │ │ ├── ReleaseType.java │ │ │ ├── RepoDb.java │ │ │ ├── RepoDbDefinitions.java │ │ │ ├── RepoParser.java │ │ │ └── Repository.java │ │ │ ├── util │ │ │ ├── AssetUtil.java │ │ │ ├── DownloadsUtil.java │ │ │ ├── HashUtil.java │ │ │ ├── InstallApkUtil.java │ │ │ ├── InstallZipUtil.java │ │ │ ├── ModuleUtil.java │ │ │ ├── NavUtil.java │ │ │ ├── NotificationUtil.java │ │ │ ├── PrefixedSharedPreferences.java │ │ │ ├── RepoLoader.java │ │ │ ├── RootUtil.java │ │ │ ├── ThemeUtil.java │ │ │ ├── chrome │ │ │ │ ├── CustomTabActivityHelper.java │ │ │ │ ├── CustomTabsHelper.java │ │ │ │ ├── CustomTabsURLSpan.java │ │ │ │ ├── LinkTransformationMethod.java │ │ │ │ ├── ServiceConnection.java │ │ │ │ └── ServiceConnectionCallback.java │ │ │ └── json │ │ │ │ ├── JSONUtils.java │ │ │ │ ├── XposedTab.java │ │ │ │ └── XposedZip.java │ │ │ └── widget │ │ │ ├── DownloadView.java │ │ │ ├── IconListPreference.java │ │ │ ├── IntegerListPreference.java │ │ │ └── ListPreferenceSummaryFix.java │ │ └── res │ │ ├── anim │ │ ├── fade_in.xml │ │ └── fade_out.xml │ │ ├── drawable-anydpi │ │ ├── ic_action_share.xml │ │ ├── ic_action_thumb_down.xml │ │ ├── ic_action_thumb_up.xml │ │ ├── ic_android.xml │ │ ├── ic_bookmark.xml │ │ ├── ic_bookmark_outline.xml │ │ ├── ic_check_circle.xml │ │ ├── ic_chip.xml │ │ ├── ic_close.xml │ │ ├── ic_delete.xml │ │ ├── ic_description.xml │ │ ├── ic_donate.xml │ │ ├── ic_error.xml │ │ ├── ic_github.xml │ │ ├── ic_help.xml │ │ ├── ic_history.xml │ │ ├── ic_info.xml │ │ ├── ic_language.xml │ │ ├── ic_manufacturer.xml │ │ ├── ic_menu_refresh.xml │ │ ├── ic_menu_search.xml │ │ ├── ic_menu_sort.xml │ │ ├── ic_nav_about.xml │ │ ├── ic_nav_downloads.xml │ │ ├── ic_nav_install.xml │ │ ├── ic_nav_logs.xml │ │ ├── ic_nav_modules.xml │ │ ├── ic_nav_settings.xml │ │ ├── ic_nav_support.xml │ │ ├── ic_no_connection.xml │ │ ├── ic_no_image.xml │ │ ├── ic_notification.xml │ │ ├── ic_person.xml │ │ ├── ic_save.xml │ │ ├── ic_scroll_down.xml │ │ ├── ic_scroll_top.xml │ │ ├── ic_send.xml │ │ ├── ic_update.xml │ │ ├── ic_warning.xml │ │ ├── ic_warning_grey.xml │ │ ├── ic_xda.xml │ │ ├── shortcut_ic_downloads.xml │ │ └── shortcut_ic_modules.xml │ │ ├── drawable │ │ ├── background_card_black.xml │ │ ├── background_card_dark.xml │ │ ├── background_card_light.xml │ │ ├── background_card_normal_black.xml │ │ ├── background_card_normal_dark.xml │ │ ├── background_card_normal_light.xml │ │ ├── background_card_pressed_black.xml │ │ ├── background_card_pressed_dark.xml │ │ ├── background_card_pressed_light.xml │ │ ├── ic_flash.xml │ │ ├── ic_verified.xml │ │ └── toolbar_shadow.xml │ │ ├── layout-v23 │ │ └── list_item_download.xml │ │ ├── layout │ │ ├── activity_container.xml │ │ ├── activity_download_details.xml │ │ ├── activity_download_details_not_found.xml │ │ ├── activity_installation.xml │ │ ├── activity_welcome.xml │ │ ├── card_authors.xml │ │ ├── color_icon_preview.xml │ │ ├── dialog_install_warning.xml │ │ ├── download_details.xml │ │ ├── download_moreinfo.xml │ │ ├── download_view.xml │ │ ├── icon_preference_item.xml │ │ ├── list_fragment.xml │ │ ├── list_item_download.xml │ │ ├── list_item_module.xml │ │ ├── list_item_version.xml │ │ ├── list_sticky_header_download.xml │ │ ├── single_installer_view.xml │ │ ├── status_installer.xml │ │ ├── tab_about.xml │ │ ├── tab_advanced_installer.xml │ │ ├── tab_downloader.xml │ │ ├── tab_logs.xml │ │ ├── tab_support.xml │ │ ├── toolbar.xml │ │ └── xposed_not_active_note.xml │ │ ├── menu │ │ ├── context_menu_modules.xml │ │ ├── context_menu_modules_bookmark.xml │ │ ├── drawer.xml │ │ ├── menu_about.xml │ │ ├── menu_download.xml │ │ ├── menu_download_details.xml │ │ ├── menu_installer.xml │ │ ├── menu_logs.xml │ │ └── menu_modules.xml │ │ ├── mipmap-hdpi │ │ ├── circle_ic_launcher.png │ │ ├── circle_ic_launcher_hjmodi.png │ │ ├── circle_ic_launcher_rovo.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_hjmodi.png │ │ ├── ic_launcher_rovo.png │ │ ├── ic_launcher_rovo_old.png │ │ └── ic_launcher_staol.png │ │ ├── mipmap-mdpi │ │ ├── circle_ic_launcher.png │ │ ├── circle_ic_launcher_hjmodi.png │ │ ├── circle_ic_launcher_rovo.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_hjmodi.png │ │ ├── ic_launcher_rovo.png │ │ ├── ic_launcher_rovo_old.png │ │ └── ic_launcher_staol.png │ │ ├── mipmap-xhdpi │ │ ├── circle_ic_launcher.png │ │ ├── circle_ic_launcher_hjmodi.png │ │ ├── circle_ic_launcher_rovo.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_hjmodi.png │ │ ├── ic_launcher_rovo.png │ │ ├── ic_launcher_rovo_old.png │ │ └── ic_launcher_staol.png │ │ ├── mipmap-xxhdpi │ │ ├── circle_ic_launcher.png │ │ ├── circle_ic_launcher_hjmodi.png │ │ ├── circle_ic_launcher_rovo.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_hjmodi.png │ │ ├── ic_launcher_rovo.png │ │ └── ic_launcher_staol.png │ │ ├── mipmap-xxxhdpi │ │ ├── circle_ic_launcher.png │ │ ├── circle_ic_launcher_hjmodi.png │ │ ├── circle_ic_launcher_rovo.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_hjmodi.png │ │ └── ic_launcher_staol.png │ │ ├── values-ar │ │ └── strings.xml │ │ ├── values-az │ │ └── 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-fr │ │ └── strings.xml │ │ ├── values-gl │ │ └── strings.xml │ │ ├── values-hi │ │ └── strings.xml │ │ ├── values-hu │ │ └── strings.xml │ │ ├── values-in │ │ └── strings.xml │ │ ├── values-it │ │ └── strings.xml │ │ ├── values-iw │ │ └── strings.xml │ │ ├── values-ja │ │ └── strings.xml │ │ ├── values-ko │ │ └── strings.xml │ │ ├── values-ms │ │ └── strings.xml │ │ ├── values-nb │ │ └── strings.xml │ │ ├── values-nl │ │ └── strings.xml │ │ ├── values-pl │ │ └── strings.xml │ │ ├── values-pt-rBR │ │ └── strings.xml │ │ ├── values-pt │ │ └── strings.xml │ │ ├── values-ro │ │ └── strings.xml │ │ ├── values-ru │ │ └── strings.xml │ │ ├── values-sk │ │ └── strings.xml │ │ ├── values-sr │ │ └── strings.xml │ │ ├── values-sv │ │ └── strings.xml │ │ ├── values-sw600dp-v21 │ │ └── styles.xml │ │ ├── values-sw600dp │ │ ├── bool.xml │ │ └── styles.xml │ │ ├── values-th │ │ └── strings.xml │ │ ├── values-tr │ │ └── strings.xml │ │ ├── values-uk │ │ └── strings.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-vi │ │ └── strings.xml │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ ├── values-zh-rTW │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── bool.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── donottranslate.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── file_paths.xml │ │ ├── module_prefs.xml │ │ ├── prefs.xml │ │ └── shortcuts.xml ├── wanam-xposed-uninstaller-20160211.zip ├── xposed_list.json └── xposed_list_v2.json ├── art ├── Phone_About.png ├── Phone_DownloadList.png ├── Phone_Installed.png ├── Phone_Logs.png ├── Phone_NougatError.png ├── Phone_Settings.png ├── Phone_Settings2.png ├── Phone_Settings3.png ├── Phone_SingleInstaller.png ├── Phone_Support.png ├── Phone_Warning.png ├── Tablet_About.png ├── Tablet_Bookmarks.png ├── Tablet_DownloadList.png ├── Tablet_InAppBrowser.png ├── Tablet_Logs.png ├── Tablet_ModuleDetails.png ├── Tablet_ModuleDetails_Bookmark.png ├── Tablet_Settings.png ├── Tablet_SingleInstaller.png ├── Tablet_Support.png └── Tablet_Welcome.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── proguard-project.txt └── settings.gradle /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ###### Include the following: 2 | - Xposed Version: `85` 3 | - [ ] Xposed Systemless 4 | - Device OS version: `6.0.1` 5 | - Device Manufacturer: `LG` 6 | - Device Name: `Nexus 5` 7 | - Material Xposed Installer version: `14/09/2016` 8 | 9 | ###### Reproduction Steps 10 | 11 | 1. 12 | 2. 13 | 3. 14 | 15 | ###### Expected Result 16 | 17 | 18 | ###### Actual Result 19 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | _If your pull request is a translation update, then the title of this pull must contains 'string' or 'translation'_ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.apk 2 | *.ap_ 3 | *.iml 4 | *.dex 5 | *.class 6 | .idea/ 7 | .gradle/ 8 | build/ 9 | local.properties 10 | app/lint.xml 11 | app/proguard-project.txt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - tools 8 | - build-tools-28.0.3 9 | - android-28 10 | - extra-android-support 11 | - extra-android-m2repository 12 | - extra-google-m2repository 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | XposedInstaller 2 | =============== 3 | [![Build Status](https://travis-ci.org/DVDAndroid/XposedInstaller.svg?branch=material)](https://travis-ci.org/DVDAndroid/XposedInstaller) 4 | 5 | This is a materialised version of Xposed Installer 6 | 7 | [Show this project on XDA](http://forum.xda-developers.com/xposed/material-design-xposed-installer-t3137758) 8 | 9 | Credits 10 | ------- 11 | 12 | [rovo89](https://github.com/rovo89) for original XposedInstaller 13 | [BioHaZard1](https://github.com/BioHaZard1) for graphics changes 14 | 15 | [afollestad](https://github.com/afollestad) for his [material-dialogs](https://github.com/afollestad/material-dialogs) library 16 | -------------------------------------------------------------------------------- /XposedInstaller.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/Xposed-Disabler-Recovery.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/Xposed-Disabler-Recovery.zip -------------------------------------------------------------------------------- /app/Xposed-Installer-Recovery.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/Xposed-Installer-Recovery.zip -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | ext { 4 | VERSION_DATE = '18/05/19' 5 | SUPPORT_LIBRARY_VERSION = '27.0.2' 6 | BUILD_TOOLS = "28.0.3" 7 | APP_VERSION = '"1558200000000"' 8 | } 9 | 10 | android { 11 | compileSdkVersion 27 12 | buildToolsVersion BUILD_TOOLS 13 | 14 | lintOptions { 15 | abortOnError false 16 | } 17 | 18 | defaultConfig { 19 | applicationId "de.robv.android.xposed.installer" 20 | minSdkVersion 16 21 | //noinspection OldTargetApi 22 | targetSdkVersion 25 23 | versionCode 42 24 | versionName "3.1.5 by dvdandroid - " + VERSION_DATE 25 | project.ext.set("archivesBaseName", "XposedInstaller_by_dvdandroid_" + VERSION_DATE.replaceAll("/", "_")) 26 | 27 | buildConfigField "String", "APP_VERSION", APP_VERSION 28 | } 29 | 30 | buildTypes { 31 | release { 32 | minifyEnabled false 33 | } 34 | } 35 | } 36 | 37 | dependencies { 38 | implementation "com.android.support:cardview-v7:$SUPPORT_LIBRARY_VERSION" 39 | implementation "com.android.support:design:$SUPPORT_LIBRARY_VERSION" 40 | implementation "com.android.support:customtabs:$SUPPORT_LIBRARY_VERSION" 41 | implementation 'com.afollestad.material-dialogs:commons:0.9.0.2' 42 | implementation 'com.github.machinarius:preferencefragment:0.1.1' 43 | implementation 'com.github.mtotschnig:StickyListHeaders:2.7.1' 44 | implementation 'eu.chainfire:libsuperuser:1.0.0.201608240809' 45 | implementation 'com.squareup.picasso:picasso:2.5.2' 46 | implementation 'de.psdev.licensesdialog:licensesdialog:1.8.3' 47 | implementation 'com.annimon:stream:1.1.9' 48 | implementation 'com.google.code.gson:gson:2.8.2' 49 | implementation fileTree(include: ['*.jar'], dir: 'libs') 50 | } 51 | -------------------------------------------------------------------------------- /app/libs/AndroidHiddenAPI.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/libs/AndroidHiddenAPI.jar -------------------------------------------------------------------------------- /app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/proguard-project.txt: -------------------------------------------------------------------------------- 1 | -dontobfuscate 2 | 3 | # These are mostly picked from proguard-android-optimize.txt 4 | -optimizations !code/allocation/variable,!code/simplification/cast,!field/*,!class/merging/* 5 | -optimizationpasses 5 6 | -allowaccessmodification 7 | -dontpreverify 8 | 9 | -dontusemixedcaseclassnames 10 | -dontskipnonpubliclibraryclasses 11 | -verbose 12 | 13 | # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations 14 | -keepclassmembers enum * { 15 | public static **[] values(); 16 | public static ** valueOf(java.lang.String); 17 | } 18 | 19 | -keepclassmembers class **.R$* { 20 | public static ; 21 | } 22 | 23 | # The support library contains references to newer platform versions. 24 | # Don't warn about those in case this app is linking against an older 25 | # platform version. We know about them, and they are safe. 26 | -dontwarn android.support.** 27 | 28 | # These are ok as well 29 | -dontwarn android.os.FileUtils 30 | -dontwarn com.emilsjolander.components.stickylistheaders.** 31 | -dontwarn com.squareup.picasso.** -------------------------------------------------------------------------------- /app/src/main/assets/XposedBridge.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/XposedBridge.jar -------------------------------------------------------------------------------- /app/src/main/assets/arm/app_process_xposed_sdk15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/arm/app_process_xposed_sdk15 -------------------------------------------------------------------------------- /app/src/main/assets/arm/app_process_xposed_sdk16: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/arm/app_process_xposed_sdk16 -------------------------------------------------------------------------------- /app/src/main/assets/arm/app_process_xposed_sdk19: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/arm/app_process_xposed_sdk19 -------------------------------------------------------------------------------- /app/src/main/assets/arm/busybox-xposed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/arm/busybox-xposed -------------------------------------------------------------------------------- /app/src/main/assets/x86/app_process_xposed_sdk15: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/x86/app_process_xposed_sdk15 -------------------------------------------------------------------------------- /app/src/main/assets/x86/app_process_xposed_sdk16: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/x86/app_process_xposed_sdk16 -------------------------------------------------------------------------------- /app/src/main/assets/x86/app_process_xposed_sdk19: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/x86/app_process_xposed_sdk19 -------------------------------------------------------------------------------- /app/src/main/assets/x86/busybox-xposed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/dbf0763631715db8ac69b58e294dc227bc0ef204/app/src/main/assets/x86/busybox-xposed -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsFragment.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer; 2 | 3 | import android.app.Activity; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.text.method.LinkMovementMethod; 8 | import android.util.Pair; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.TextView; 13 | 14 | import de.robv.android.xposed.installer.repo.Module; 15 | import de.robv.android.xposed.installer.repo.RepoParser; 16 | import de.robv.android.xposed.installer.util.NavUtil; 17 | import de.robv.android.xposed.installer.util.chrome.LinkTransformationMethod; 18 | 19 | public class DownloadDetailsFragment extends Fragment { 20 | private DownloadDetailsActivity mActivity; 21 | 22 | @Override 23 | public void onAttach(Activity activity) { 24 | super.onAttach(activity); 25 | mActivity = (DownloadDetailsActivity) activity; 26 | } 27 | 28 | @Override 29 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 30 | final Module module = mActivity.getModule(); 31 | if (module == null) 32 | return null; 33 | 34 | final View view = inflater.inflate(R.layout.download_details, container, false); 35 | 36 | TextView title = view.findViewById(R.id.download_title); 37 | title.setText(module.name); 38 | title.setTextIsSelectable(true); 39 | 40 | TextView author = view.findViewById(R.id.download_author); 41 | if (module.author != null && !module.author.isEmpty()) 42 | author.setText(getString(R.string.download_author, module.author)); 43 | else 44 | author.setText(R.string.download_unknown_author); 45 | 46 | TextView description = view.findViewById(R.id.download_description); 47 | if (module.description != null) { 48 | if (module.descriptionIsHtml) { 49 | description.setText(RepoParser.parseSimpleHtml(getActivity(), module.description, description)); 50 | description.setTransformationMethod(new LinkTransformationMethod(getActivity())); 51 | description.setMovementMethod(LinkMovementMethod.getInstance()); 52 | } else { 53 | description.setText(module.description); 54 | } 55 | description.setTextIsSelectable(true); 56 | } else { 57 | description.setVisibility(View.GONE); 58 | } 59 | 60 | ViewGroup moreInfoContainer = view.findViewById(R.id.download_moreinfo_container); 61 | for (Pair moreInfoEntry : module.moreInfo) { 62 | View moreInfoView = inflater.inflate(R.layout.download_moreinfo, moreInfoContainer, false); 63 | TextView txtTitle = moreInfoView.findViewById(android.R.id.title); 64 | TextView txtValue = moreInfoView.findViewById(android.R.id.message); 65 | 66 | txtTitle.setText(moreInfoEntry.first + ":"); 67 | txtValue.setText(moreInfoEntry.second); 68 | 69 | final Uri link = NavUtil.parseURL(moreInfoEntry.second); 70 | if (link != null) { 71 | txtValue.setTextColor(txtValue.getLinkTextColors()); 72 | moreInfoView.setOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View v) { 75 | NavUtil.startURL(getActivity(), link); 76 | } 77 | }); 78 | } 79 | 80 | moreInfoContainer.addView(moreInfoView); 81 | } 82 | 83 | return view; 84 | } 85 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsSettingsFragment.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | import android.os.Bundle; 7 | import android.preference.Preference; 8 | import android.preference.Preference.OnPreferenceChangeListener; 9 | import android.preference.PreferenceManager; 10 | 11 | import com.github.machinarius.preferencefragment.PreferenceFragment; 12 | 13 | import java.util.Map; 14 | 15 | import de.robv.android.xposed.installer.repo.Module; 16 | import de.robv.android.xposed.installer.util.PrefixedSharedPreferences; 17 | import de.robv.android.xposed.installer.util.RepoLoader; 18 | 19 | public class DownloadDetailsSettingsFragment extends PreferenceFragment { 20 | private DownloadDetailsActivity mActivity; 21 | 22 | @Override 23 | public void onAttach(Activity activity) { 24 | super.onAttach(activity); 25 | mActivity = (DownloadDetailsActivity) activity; 26 | } 27 | 28 | @Override 29 | public void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | 32 | final Module module = mActivity.getModule(); 33 | if (module == null) 34 | return; 35 | 36 | final String packageName = module.packageName; 37 | 38 | PreferenceManager prefManager = getPreferenceManager(); 39 | prefManager.setSharedPreferencesName("module_settings"); 40 | PrefixedSharedPreferences.injectToPreferenceManager(prefManager, module.packageName); 41 | addPreferencesFromResource(R.xml.module_prefs); 42 | 43 | SharedPreferences prefs = getActivity().getSharedPreferences("module_settings", Context.MODE_PRIVATE); 44 | SharedPreferences.Editor editor = prefs.edit(); 45 | 46 | if (prefs.getBoolean("no_global", true)) { 47 | for (Map.Entry k : prefs.getAll().entrySet()) { 48 | if (prefs.getString(k.getKey(), "").equals("global")) { 49 | editor.putString(k.getKey(), "").apply(); 50 | } 51 | } 52 | 53 | editor.putBoolean("no_global", false).apply(); 54 | } 55 | 56 | findPreference("release_type").setOnPreferenceChangeListener( 57 | new OnPreferenceChangeListener() { 58 | @Override 59 | public boolean onPreferenceChange(Preference preference, 60 | Object newValue) { 61 | RepoLoader.getInstance().setReleaseTypeLocal(packageName, (String) newValue); 62 | return true; 63 | } 64 | }); 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/SupportActivity.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.widget.Toolbar; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import de.robv.android.xposed.installer.util.NavUtil; 14 | import de.robv.android.xposed.installer.util.ThemeUtil; 15 | 16 | import static de.robv.android.xposed.installer.XposedApp.darkenColor; 17 | 18 | public class SupportActivity extends XposedBaseActivity { 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | ThemeUtil.setTheme(this); 23 | setContentView(R.layout.activity_container); 24 | 25 | Toolbar toolbar = findViewById(R.id.toolbar); 26 | setSupportActionBar(toolbar); 27 | 28 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View view) { 31 | finish(); 32 | } 33 | }); 34 | 35 | ActionBar ab = getSupportActionBar(); 36 | if (ab != null) { 37 | ab.setTitle(R.string.nav_item_support); 38 | ab.setDisplayHomeAsUpEnabled(true); 39 | } 40 | 41 | setFloating(toolbar, 0); 42 | 43 | if (savedInstanceState == null) { 44 | getSupportFragmentManager().beginTransaction().add(R.id.container, new SupportFragment()).commit(); 45 | } 46 | } 47 | 48 | public static class SupportFragment extends Fragment { 49 | @Override 50 | public void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | } 53 | 54 | @Override 55 | public void onResume() { 56 | super.onResume(); 57 | if (Build.VERSION.SDK_INT >= 21) 58 | getActivity().getWindow().setStatusBarColor(darkenColor(XposedApp.getColor(getActivity()), 0.85f)); 59 | } 60 | 61 | @Override 62 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 63 | Bundle savedInstanceState) { 64 | View v = inflater.inflate(R.layout.tab_support, container, false); 65 | 66 | View installerSupportView = v.findViewById(R.id.installerSupportView); 67 | View faqView = v.findViewById(R.id.faqView); 68 | View donateView = v.findViewById(R.id.donateView); 69 | TextView txtModuleSupport = v.findViewById(R.id.tab_support_module_description); 70 | 71 | txtModuleSupport.setText(getString(R.string.support_modules_description, 72 | getString(R.string.module_support))); 73 | 74 | setupView(installerSupportView, R.string.support_material_xda); 75 | setupView(faqView, R.string.support_faq_url); 76 | setupView(donateView, R.string.support_donate_url); 77 | 78 | return v; 79 | } 80 | 81 | public void setupView(View v, final int url) { 82 | v.setOnClickListener(new View.OnClickListener() { 83 | @Override 84 | public void onClick(View v) { 85 | NavUtil.startURL(getActivity(), getString(url)); 86 | } 87 | }); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/XposedBaseActivity.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.StringRes; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.WindowManager; 7 | 8 | import de.robv.android.xposed.installer.util.ThemeUtil; 9 | 10 | public abstract class XposedBaseActivity extends AppCompatActivity { 11 | public int mTheme = -1; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceBundle) { 15 | super.onCreate(savedInstanceBundle); 16 | ThemeUtil.setTheme(this); 17 | } 18 | 19 | @Override 20 | protected void onResume() { 21 | super.onResume(); 22 | XposedApp.setColors(getSupportActionBar(), XposedApp.getColor(this), this); 23 | ThemeUtil.reloadTheme(this); 24 | } 25 | 26 | public void setFloating(android.support.v7.widget.Toolbar toolbar, @StringRes int details) { 27 | boolean isTablet = getResources().getBoolean(R.bool.isTablet); 28 | if (isTablet) { 29 | WindowManager.LayoutParams params = getWindow().getAttributes(); 30 | params.height = getResources().getDimensionPixelSize(R.dimen.floating_height); 31 | params.width = getResources().getDimensionPixelSize(R.dimen.floating_width); 32 | params.alpha = 1.0f; 33 | params.dimAmount = 0.6f; 34 | params.flags |= 2; 35 | getWindow().setAttributes(params); 36 | 37 | if (details != 0) { 38 | toolbar.setTitle(details); 39 | } 40 | toolbar.setNavigationIcon(R.drawable.ic_close); 41 | setFinishOnTouchOutside(true); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/installation/FlashCallback.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.installation; 2 | 3 | import de.robv.android.xposed.installer.util.RootUtil; 4 | import eu.chainfire.libsuperuser.Shell; 5 | 6 | public interface FlashCallback extends RootUtil.LineCallback { 7 | void onStarted(); 8 | void onDone(); 9 | void onError(int exitCode, String error); 10 | 11 | int OK = 0; 12 | int ERROR_GENERIC = 1; 13 | 14 | // SU errors 15 | int ERROR_TIMEOUT = Shell.OnCommandResultListener.WATCHDOG_EXIT; 16 | int ERROR_SHELL_DIED = Shell.OnCommandResultListener.SHELL_DIED; 17 | int ERROR_NO_ROOT_ACCESS = Shell.OnCommandResultListener.SHELL_EXEC_FAILED; 18 | 19 | // ZIP errors 20 | int ERROR_INVALID_ZIP = -100; 21 | int ERROR_NOT_FLASHABLE_IN_APP = -101; 22 | int ERROR_INSTALLER_NEEDS_UPDATE = -102; 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/installation/FlashDirectly.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.installation; 2 | 3 | import android.content.Context; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | import android.util.Log; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.util.Set; 11 | import java.util.zip.ZipEntry; 12 | import java.util.zip.ZipFile; 13 | 14 | import de.robv.android.xposed.installer.XposedApp; 15 | import de.robv.android.xposed.installer.util.AssetUtil; 16 | import de.robv.android.xposed.installer.util.InstallZipUtil; 17 | import de.robv.android.xposed.installer.util.RootUtil; 18 | 19 | import static de.robv.android.xposed.installer.util.InstallZipUtil.closeSilently; 20 | import static de.robv.android.xposed.installer.util.InstallZipUtil.reportMissingFeatures; 21 | import static de.robv.android.xposed.installer.util.InstallZipUtil.triggerError; 22 | import static de.robv.android.xposed.installer.util.RootUtil.getShellPath; 23 | 24 | public class FlashDirectly extends Flashable { 25 | public static final Parcelable.Creator CREATOR 26 | = new Parcelable.Creator() { 27 | @Override 28 | public FlashDirectly createFromParcel(Parcel in) { 29 | return new FlashDirectly(in); 30 | } 31 | 32 | @Override 33 | public FlashDirectly[] newArray(int size) { 34 | return new FlashDirectly[size]; 35 | } 36 | }; 37 | private final boolean mSystemless; 38 | 39 | public FlashDirectly(String zipPath, boolean systemless) { 40 | super(new File(zipPath)); 41 | mSystemless = systemless; 42 | } 43 | 44 | protected FlashDirectly(Parcel in) { 45 | super(in); 46 | mSystemless = in.readInt() == 1; 47 | } 48 | 49 | public void flash(Context context, FlashCallback callback) { 50 | InstallZipUtil.ZipCheckResult zipCheck = openAndCheckZip(callback); 51 | if (zipCheck == null) { 52 | return; 53 | } 54 | 55 | ZipFile zip = zipCheck.getZip(); 56 | if (!zipCheck.isFlashableInApp()) { 57 | triggerError(callback, FlashCallback.ERROR_NOT_FLASHABLE_IN_APP); 58 | closeSilently(zip); 59 | return; 60 | } 61 | 62 | // Extract update-binary. 63 | ZipEntry entry = zip.getEntry("META-INF/com/google/android/update-binary"); 64 | File updateBinaryFile = new File(XposedApp.getInstance().getCacheDir(), "update-binary"); 65 | try { 66 | AssetUtil.writeStreamToFile(zip.getInputStream(entry), updateBinaryFile, 0700); 67 | } catch (IOException e) { 68 | Log.e(XposedApp.TAG, "Could not extract update-binary", e); 69 | triggerError(callback, FlashCallback.ERROR_INVALID_ZIP); 70 | return; 71 | } finally { 72 | closeSilently(zip); 73 | } 74 | 75 | // Execute the flash commands. 76 | RootUtil rootUtil = new RootUtil(); 77 | if (!rootUtil.startShell(callback)) { 78 | return; 79 | } 80 | 81 | callback.onStarted(); 82 | 83 | rootUtil.execute("export NO_UIPRINT=1", callback); 84 | if (mSystemless) { 85 | rootUtil.execute("export SYSTEMLESS=1", callback); 86 | } 87 | 88 | int result = rootUtil.execute(getShellPath(updateBinaryFile) + " 2 1 " + getShellPath(mZipPath), callback); 89 | if (result != 0) { 90 | triggerError(callback, result); 91 | return; 92 | } 93 | 94 | callback.onDone(); 95 | } 96 | 97 | @Override 98 | public void writeToParcel(Parcel dest, int flags) { 99 | super.writeToParcel(dest, flags); 100 | dest.writeInt(mSystemless ? 1 : 0); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/installation/FlashRecoveryAuto.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.installation; 2 | 3 | import android.content.Context; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import java.io.File; 8 | import java.util.ArrayList; 9 | 10 | import de.robv.android.xposed.installer.R; 11 | import de.robv.android.xposed.installer.util.InstallZipUtil.ZipCheckResult; 12 | import de.robv.android.xposed.installer.util.RootUtil; 13 | 14 | import static de.robv.android.xposed.installer.util.InstallZipUtil.closeSilently; 15 | 16 | public class FlashRecoveryAuto extends Flashable { 17 | 18 | public static final Parcelable.Creator CREATOR 19 | = new Parcelable.Creator() { 20 | @Override 21 | public FlashRecoveryAuto createFromParcel(Parcel in) { 22 | return new FlashRecoveryAuto(in); 23 | } 24 | 25 | @Override 26 | public FlashRecoveryAuto[] newArray(int size) { 27 | return new FlashRecoveryAuto[size]; 28 | } 29 | }; 30 | 31 | public FlashRecoveryAuto(File zipPath) { 32 | super(zipPath); 33 | } 34 | 35 | protected FlashRecoveryAuto(Parcel in) { 36 | super(in); 37 | } 38 | 39 | @Override 40 | public void flash(Context context, FlashCallback callback) { 41 | ZipCheckResult zipCheck = openAndCheckZip(callback); 42 | if (zipCheck == null) { 43 | return; 44 | } else { 45 | closeSilently(zipCheck.getZip()); 46 | } 47 | 48 | final String zipName = mZipPath.getName(); 49 | String cmd; 50 | 51 | // Execute the flash commands. 52 | RootUtil rootUtil = new RootUtil(); 53 | if (!rootUtil.startShell(callback)) { 54 | return; 55 | } 56 | 57 | callback.onStarted(); 58 | 59 | // Make sure /cache/recovery/ exists. 60 | if (rootUtil.execute("ls /cache/recovery", new ArrayList()) != 0) { 61 | callback.onLine(context.getString(R.string.file_creating_directory, "/cache/recovery")); 62 | if (rootUtil.executeWithBusybox("mkdir /cache/recovery", callback) != 0) { 63 | callback.onError(FlashCallback.ERROR_GENERIC, 64 | context.getString(R.string.file_create_directory_failed, "/cache/recovery")); 65 | return; 66 | } 67 | } 68 | 69 | // Copy the ZIP to /cache/recovery/. 70 | callback.onLine(context.getString(R.string.file_copying, zipName)); 71 | cmd = "cp -a " + RootUtil.getShellPath(mZipPath) + " /cache/recovery/" + zipName; 72 | if (rootUtil.executeWithBusybox(cmd, callback) != 0) { 73 | callback.onError(FlashCallback.ERROR_GENERIC, 74 | context.getString(R.string.file_copy_failed, zipName, "/cache/recovery")); 75 | return; 76 | } 77 | 78 | // Write the flashing command to /cache/recovery/command. 79 | callback.onLine(context.getString(R.string.file_writing_recovery_command)); 80 | cmd = "echo --update_package=/cache/recovery/" + zipName + " > /cache/recovery/command"; 81 | if (rootUtil.execute(cmd, callback) != 0) { 82 | callback.onError(FlashCallback.ERROR_GENERIC, 83 | context.getString(R.string.file_writing_recovery_command_failed)); 84 | return; 85 | } 86 | 87 | callback.onLine(context.getString(R.string.auto_flash_note, zipName)); 88 | callback.onDone(); 89 | } 90 | 91 | @Override 92 | public RootUtil.RebootMode getRebootMode() { 93 | return RootUtil.RebootMode.RECOVERY; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/installation/Flashable.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.installation; 2 | 3 | import android.content.Context; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.util.Set; 10 | import java.util.zip.ZipFile; 11 | 12 | import de.robv.android.xposed.installer.util.InstallZipUtil; 13 | import de.robv.android.xposed.installer.util.RootUtil; 14 | 15 | import static de.robv.android.xposed.installer.util.InstallZipUtil.closeSilently; 16 | import static de.robv.android.xposed.installer.util.InstallZipUtil.reportMissingFeatures; 17 | import static de.robv.android.xposed.installer.util.InstallZipUtil.triggerError; 18 | 19 | public abstract class Flashable implements Parcelable { 20 | public static final String KEY = "flash"; 21 | 22 | protected final File mZipPath; 23 | 24 | public Flashable(File zipPath) { 25 | mZipPath = zipPath; 26 | } 27 | 28 | protected Flashable(Parcel in) { 29 | mZipPath = (File) in.readSerializable(); 30 | } 31 | 32 | protected InstallZipUtil.ZipCheckResult openAndCheckZip(FlashCallback callback) { 33 | // Open the ZIP file. 34 | ZipFile zip; 35 | try { 36 | zip = new ZipFile(mZipPath); 37 | } catch (IOException e) { 38 | triggerError(callback, FlashCallback.ERROR_INVALID_ZIP, e.getLocalizedMessage()); 39 | return null; 40 | } 41 | 42 | // Do some checks. 43 | InstallZipUtil.ZipCheckResult zipCheck = InstallZipUtil.checkZip(zip); 44 | if (!zipCheck.isValidZip()) { 45 | triggerError(callback, FlashCallback.ERROR_INVALID_ZIP); 46 | closeSilently(zip); 47 | return null; 48 | } 49 | 50 | if (zipCheck.hasXposedProp()) { 51 | Set missingFeatures = zipCheck.getXposedProp().getMissingInstallerFeatures(); 52 | if (!missingFeatures.isEmpty()) { 53 | reportMissingFeatures(missingFeatures); 54 | triggerError(callback, FlashCallback.ERROR_INSTALLER_NEEDS_UPDATE); 55 | closeSilently(zip); 56 | return null; 57 | } 58 | } 59 | 60 | return zipCheck; 61 | } 62 | 63 | public abstract void flash(Context context, FlashCallback callback); 64 | 65 | public RootUtil.RebootMode getRebootMode() { 66 | return RootUtil.RebootMode.NORMAL; 67 | } 68 | 69 | @Override 70 | public int describeContents() { 71 | return 0; 72 | } 73 | 74 | @Override 75 | public void writeToParcel(Parcel dest, int flags) { 76 | dest.writeSerializable(mZipPath); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/receivers/BootReceiver.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.receivers; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.ConnectivityManager; 7 | import android.net.NetworkInfo; 8 | import android.os.AsyncTask; 9 | import android.util.Log; 10 | 11 | import org.json.JSONObject; 12 | 13 | import java.math.BigInteger; 14 | 15 | import de.robv.android.xposed.installer.BuildConfig; 16 | import de.robv.android.xposed.installer.XposedApp; 17 | import de.robv.android.xposed.installer.util.NotificationUtil; 18 | import de.robv.android.xposed.installer.util.json.JSONUtils; 19 | 20 | public class BootReceiver extends BroadcastReceiver { 21 | 22 | @Override 23 | public void onReceive(final Context context, Intent intent) { 24 | new android.os.Handler().postDelayed(new Runnable() { 25 | @Override 26 | public void run() { 27 | if (!isOnline(context)) return; 28 | 29 | new CheckUpdates().execute(); 30 | } 31 | }, 60 * 60 * 1000 /*60 min*/); 32 | } 33 | 34 | private boolean isOnline(Context context) { 35 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 36 | NetworkInfo netInfo = cm.getActiveNetworkInfo(); 37 | return netInfo != null && netInfo.isConnectedOrConnecting(); 38 | } 39 | 40 | private class CheckUpdates extends AsyncTask { 41 | 42 | @Override 43 | protected Void doInBackground(Void... params) { 44 | try { 45 | String jsonString = JSONUtils.getFileContent(JSONUtils.JSON_LINK).replace("%XPOSED_ZIP%", ""); 46 | 47 | String newApkVersion = new JSONObject(jsonString).getJSONObject("apk").getString("version"); 48 | 49 | BigInteger a = new BigInteger(BuildConfig.APP_VERSION); 50 | BigInteger b = new BigInteger(newApkVersion); 51 | 52 | if (a.compareTo(b) == -1) { 53 | NotificationUtil.showInstallerUpdateNotification(); 54 | } 55 | } catch (Exception e) { 56 | Log.d(XposedApp.TAG, e.getMessage()); 57 | } 58 | return null; 59 | } 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/receivers/DownloadReceiver.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.receivers; 2 | 3 | import android.app.DownloadManager; 4 | import android.content.BroadcastReceiver; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | 8 | import de.robv.android.xposed.installer.util.DownloadsUtil; 9 | 10 | public class DownloadReceiver extends BroadcastReceiver { 11 | @Override 12 | public void onReceive(final Context context, final Intent intent) { 13 | String action = intent.getAction(); 14 | if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { 15 | long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); 16 | DownloadsUtil.triggerDownloadFinishedCallback(context, downloadId); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/receivers/PackageChangeReceiver.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.receivers; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | 8 | import de.robv.android.xposed.installer.util.ModuleUtil; 9 | import de.robv.android.xposed.installer.util.ModuleUtil.InstalledModule; 10 | import de.robv.android.xposed.installer.util.NotificationUtil; 11 | 12 | public class PackageChangeReceiver extends BroadcastReceiver { 13 | private static ModuleUtil mModuleUtil = null; 14 | 15 | private static String getPackageName(Intent intent) { 16 | Uri uri = intent.getData(); 17 | return (uri != null) ? uri.getSchemeSpecificPart() : null; 18 | } 19 | 20 | @Override 21 | public void onReceive(final Context context, final Intent intent) { 22 | if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) 23 | // Ignore existing packages being removed in order to be updated 24 | return; 25 | 26 | String packageName = getPackageName(intent); 27 | if (packageName == null) 28 | return; 29 | 30 | if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) { 31 | // make sure that the change is for the complete package, not only a 32 | // component 33 | String[] components = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 34 | if (components != null) { 35 | boolean isForPackage = false; 36 | for (String component : components) { 37 | if (packageName.equals(component)) { 38 | isForPackage = true; 39 | break; 40 | } 41 | } 42 | if (!isForPackage) 43 | return; 44 | } 45 | } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { 46 | NotificationUtil.cancel(packageName, NotificationUtil.NOTIFICATION_MODULE_NOT_ACTIVATED_YET); 47 | return; 48 | } 49 | 50 | mModuleUtil = getModuleUtilInstance(); 51 | 52 | InstalledModule module = ModuleUtil.getInstance().reloadSingleModule(packageName); 53 | if (module == null 54 | || intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { 55 | // Package being removed, disable it if it was a previously active 56 | // Xposed mod 57 | if (mModuleUtil.isModuleEnabled(packageName)) { 58 | mModuleUtil.setModuleEnabled(packageName, false); 59 | mModuleUtil.updateModulesList(false); 60 | } 61 | return; 62 | } 63 | 64 | if (mModuleUtil.isModuleEnabled(packageName)) { 65 | mModuleUtil.updateModulesList(false); 66 | NotificationUtil.showModulesUpdatedNotification(); 67 | } else { 68 | NotificationUtil.showNotActivatedNotification(packageName, module.getAppName()); 69 | } 70 | } 71 | 72 | private ModuleUtil getModuleUtilInstance() { 73 | if (mModuleUtil == null) { 74 | mModuleUtil = ModuleUtil.getInstance(); 75 | } 76 | return mModuleUtil; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/repo/Module.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.repo; 2 | 3 | import android.util.Pair; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | public class Module { 10 | public final Repository repository; 11 | public final List> moreInfo = new LinkedList>(); 12 | public final List versions = new ArrayList(); 13 | public final List screenshots = new ArrayList(); 14 | public String packageName; 15 | public String name; 16 | public String summary; 17 | public String description; 18 | public boolean descriptionIsHtml = false; 19 | public String author; 20 | public String support; 21 | public long created = -1; 22 | public long updated = -1; 23 | 24 | /* package */ Module(Repository repository) { 25 | this.repository = repository; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/repo/ModuleVersion.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.repo; 2 | 3 | public class ModuleVersion { 4 | public final Module module; 5 | public String name; 6 | public int code; 7 | public String downloadLink; 8 | public String md5sum; 9 | public String changelog; 10 | public boolean changelogIsHtml = false; 11 | public ReleaseType relType = ReleaseType.STABLE; 12 | public long uploaded = -1; 13 | 14 | /* package */ ModuleVersion(Module module) { 15 | this.module = module; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/repo/ReleaseType.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.repo; 2 | 3 | import de.robv.android.xposed.installer.R; 4 | 5 | public enum ReleaseType { 6 | STABLE(R.string.reltype_stable, R.string.reltype_stable_summary), BETA(R.string.reltype_beta, R.string.reltype_beta_summary), EXPERIMENTAL(R.string.reltype_experimental, R.string.reltype_experimental_summary); 7 | 8 | private static final ReleaseType[] sValuesCache = values(); 9 | private final int mTitleId; 10 | private final int mSummaryId; 11 | 12 | ReleaseType(int titleId, int summaryId) { 13 | mTitleId = titleId; 14 | mSummaryId = summaryId; 15 | } 16 | 17 | public static ReleaseType fromString(String value) { 18 | if (value == null || value.equals("stable")) 19 | return STABLE; 20 | else if (value.equals("beta")) 21 | return BETA; 22 | else if (value.equals("experimental")) 23 | return EXPERIMENTAL; 24 | else 25 | return STABLE; 26 | } 27 | 28 | public static ReleaseType fromOrdinal(int ordinal) { 29 | return sValuesCache[ordinal]; 30 | } 31 | 32 | public int getTitleId() { 33 | return mTitleId; 34 | } 35 | 36 | public int getSummaryId() { 37 | return mSummaryId; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/repo/Repository.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.repo; 2 | 3 | public class Repository { 4 | public String name; 5 | public String url; 6 | public boolean isPartial = false; 7 | public String partialUrl; 8 | public String version; 9 | 10 | /* package */ Repository() { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/AssetUtil.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util; 2 | 3 | import android.content.res.AssetManager; 4 | import android.os.Build; 5 | import android.os.FileUtils; 6 | import android.util.Log; 7 | 8 | import java.io.File; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | 13 | import de.robv.android.xposed.installer.XposedApp; 14 | 15 | public class AssetUtil { 16 | public static final File BUSYBOX_FILE = new File(XposedApp.getInstance().getCacheDir(), "busybox-xposed"); 17 | 18 | @SuppressWarnings("deprecation") 19 | public static String getBinariesFolder() { 20 | if (Build.CPU_ABI.startsWith("arm")) { 21 | return "arm/"; 22 | } else if (Build.CPU_ABI.startsWith("x86")) { 23 | return "x86/"; 24 | } else { 25 | return null; 26 | } 27 | } 28 | 29 | public static File writeAssetToCacheFile(String name, int mode) { 30 | return writeAssetToCacheFile(name, name, mode); 31 | } 32 | 33 | public static File writeAssetToCacheFile(String assetName, String fileName, int mode) { 34 | return writeAssetToFile(assetName, new File(XposedApp.getInstance().getCacheDir(), fileName), mode); 35 | } 36 | 37 | public static File writeAssetToSdcardFile(String name, int mode) { 38 | return writeAssetToSdcardFile(name, name, mode); 39 | } 40 | 41 | public static File writeAssetToSdcardFile(String assetName, String fileName, int mode) { 42 | File dir = XposedApp.getInstance().getExternalFilesDir(null); 43 | return writeAssetToFile(assetName, new File(dir, fileName), mode); 44 | } 45 | 46 | public static File writeAssetToFile(String assetName, File targetFile, int mode) { 47 | return writeAssetToFile(null, assetName, targetFile, mode); 48 | } 49 | 50 | public static File writeAssetToFile(AssetManager assets, String assetName, File targetFile, int mode) { 51 | try { 52 | if (assets == null) 53 | assets = XposedApp.getInstance().getAssets(); 54 | InputStream in = assets.open(assetName); 55 | writeStreamToFile(in, targetFile, mode); 56 | return targetFile; 57 | } catch (IOException e) { 58 | Log.e(XposedApp.TAG, "AssetUtil -> could not extract asset", e); 59 | if (targetFile != null) 60 | targetFile.delete(); 61 | 62 | return null; 63 | } 64 | } 65 | 66 | public static void writeStreamToFile(InputStream in, File targetFile, int mode) throws IOException { 67 | FileOutputStream out = new FileOutputStream(targetFile); 68 | 69 | byte[] buffer = new byte[1024]; 70 | int len; 71 | while ((len = in.read(buffer)) > 0) { 72 | out.write(buffer, 0, len); 73 | } 74 | in.close(); 75 | out.close(); 76 | 77 | FileUtils.setPermissions(targetFile.getAbsolutePath(), mode, -1, -1); 78 | } 79 | 80 | public synchronized static void extractBusybox() { 81 | if (BUSYBOX_FILE.exists()) 82 | return; 83 | 84 | AssetManager assets = null; 85 | writeAssetToFile(assets, getBinariesFolder() + "busybox-xposed", BUSYBOX_FILE, 00700); 86 | } 87 | 88 | public synchronized static void removeBusybox() { 89 | BUSYBOX_FILE.delete(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/HashUtil.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.security.MessageDigest; 8 | import java.security.NoSuchAlgorithmException; 9 | 10 | public class HashUtil { 11 | public static final String hash(String input, String algorithm) { 12 | try { 13 | MessageDigest md = MessageDigest.getInstance(algorithm); 14 | byte[] messageDigest = md.digest(input.getBytes()); 15 | return toHexString(messageDigest); 16 | } catch (NoSuchAlgorithmException e) { 17 | throw new IllegalArgumentException(e); 18 | } 19 | } 20 | 21 | public static final String md5(String input) { 22 | return hash(input, "MD5"); 23 | } 24 | 25 | public static final String sha1(String input) { 26 | return hash(input, "SHA-1"); 27 | } 28 | 29 | public static final String hash(File file, String algorithm) throws IOException { 30 | try { 31 | MessageDigest md = MessageDigest.getInstance(algorithm); 32 | InputStream is = new FileInputStream(file); 33 | byte[] buffer = new byte[8192]; 34 | int read = 0; 35 | while ((read = is.read(buffer)) > 0) { 36 | md.update(buffer, 0, read); 37 | } 38 | is.close(); 39 | byte[] messageDigest = md.digest(); 40 | return toHexString(messageDigest); 41 | } catch (NoSuchAlgorithmException e) { 42 | throw new IllegalArgumentException(e); 43 | } 44 | } 45 | 46 | public static final String md5(File input) throws IOException { 47 | return hash(input, "MD5"); 48 | } 49 | 50 | public static final String sha1(File input) throws IOException { 51 | return hash(input, "SHA-1"); 52 | } 53 | 54 | private static String toHexString(byte[] bytes) { 55 | StringBuilder sb = new StringBuilder(); 56 | for (byte b : bytes) { 57 | int unsignedB = b & 0xff; 58 | if (unsignedB < 0x10) 59 | sb.append("0"); 60 | sb.append(Integer.toHexString(unsignedB)); 61 | } 62 | return sb.toString(); 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/InstallApkUtil.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | import android.net.Uri; 7 | import android.os.AsyncTask; 8 | import android.os.Build; 9 | import android.support.v4.content.FileProvider; 10 | 11 | import java.io.File; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | import java.util.regex.Matcher; 15 | import java.util.regex.Pattern; 16 | 17 | import de.robv.android.xposed.installer.R; 18 | import de.robv.android.xposed.installer.XposedApp; 19 | 20 | public class InstallApkUtil extends AsyncTask { 21 | 22 | private static final int ERROR_ROOT_NOT_GRANTED = -99; 23 | 24 | private final DownloadsUtil.DownloadInfo info; 25 | private final Context context; 26 | private RootUtil mRootUtil; 27 | private boolean isApkRootInstallOn; 28 | private List output = new LinkedList<>(); 29 | 30 | public InstallApkUtil(Context context, DownloadsUtil.DownloadInfo info) { 31 | this.context = context; 32 | this.info = info; 33 | 34 | mRootUtil = new RootUtil(); 35 | } 36 | 37 | public static void installApkNormally(Context context, String localFilename) { 38 | Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); 39 | installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 40 | Uri uri; 41 | if (Build.VERSION.SDK_INT >= 24) { 42 | uri = FileProvider.getUriForFile(context, "de.robv.android.xposed.installer.fileprovider", new File(localFilename)); 43 | installIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 44 | } else { 45 | uri = Uri.fromFile(new File(localFilename)); 46 | } 47 | installIntent.setDataAndType(uri, DownloadsUtil.MIME_TYPE_APK); 48 | installIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, context.getApplicationInfo().packageName); 49 | context.startActivity(installIntent); 50 | } 51 | 52 | @Override 53 | protected void onPreExecute() { 54 | super.onPreExecute(); 55 | 56 | SharedPreferences prefs = XposedApp.getPreferences(); 57 | isApkRootInstallOn = prefs.getBoolean("install_with_su", false); 58 | 59 | if (isApkRootInstallOn) { 60 | NotificationUtil.showModuleInstallingNotification(info.title); 61 | mRootUtil.startShell(); 62 | } 63 | } 64 | 65 | @Override 66 | protected Integer doInBackground(Void... params) { 67 | int returnCode = 0; 68 | if (isApkRootInstallOn) { 69 | try { 70 | returnCode = mRootUtil.execute("pm install -r \"" + info.localFilename + "\"", output); 71 | } catch (IllegalStateException e) { 72 | returnCode = ERROR_ROOT_NOT_GRANTED; 73 | } 74 | } 75 | return returnCode; 76 | } 77 | 78 | @Override 79 | protected void onPostExecute(Integer result) { 80 | super.onPostExecute(result); 81 | 82 | if (isApkRootInstallOn) { 83 | NotificationUtil.cancel(NotificationUtil.NOTIFICATION_MODULE_INSTALLING); 84 | 85 | if (result.equals(ERROR_ROOT_NOT_GRANTED)) { 86 | NotificationUtil.showModuleInstallNotification(R.string.installation_error, R.string.root_failed, info.localFilename); 87 | return; 88 | } 89 | 90 | StringBuilder out = new StringBuilder(); 91 | for (Object o : output) { 92 | out.append(o.toString()); 93 | out.append("\n"); 94 | } 95 | 96 | Pattern failurePattern = Pattern.compile("(?m)^Failure\\s+\\[(.*?)\\]$"); 97 | Matcher failureMatcher = failurePattern.matcher(out); 98 | 99 | if (result.equals(0)) { 100 | NotificationUtil.showModuleInstallNotification(R.string.installation_successful, R.string.installation_successful_message, info.localFilename, info.title); 101 | } else if (failureMatcher.find()) { 102 | NotificationUtil.showModuleInstallNotification(R.string.installation_error, R.string.installation_error_message, info.localFilename, info.title, failureMatcher.group(1)); 103 | } 104 | } else { 105 | installApkNormally(context, info.localFilename); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/NavUtil.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.provider.Browser; 8 | import android.support.annotation.AnyThread; 9 | import android.support.annotation.NonNull; 10 | import android.support.customtabs.CustomTabsIntent; 11 | import android.text.Spannable; 12 | import android.text.SpannableString; 13 | import android.text.style.URLSpan; 14 | import android.text.util.Linkify; 15 | 16 | import com.afollestad.materialdialogs.MaterialDialog; 17 | 18 | import de.robv.android.xposed.installer.XposedApp; 19 | 20 | public final class NavUtil { 21 | 22 | public static Uri parseURL(String str) { 23 | if (str == null || str.isEmpty()) 24 | return null; 25 | 26 | Spannable spannable = new SpannableString(str); 27 | Linkify.addLinks(spannable, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES); 28 | 29 | URLSpan spans[] = spannable.getSpans(0, spannable.length(), URLSpan.class); 30 | return (spans.length > 0) ? Uri.parse(spans[0].getURL()) : null; 31 | } 32 | 33 | public static void startURL(Activity activity, Uri uri) { 34 | if (!XposedApp.getPreferences().getBoolean("chrome_tabs", true)) { 35 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 36 | intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()); 37 | activity.startActivity(intent); 38 | return; 39 | } 40 | 41 | CustomTabsIntent.Builder customTabsIntent = new CustomTabsIntent.Builder(); 42 | customTabsIntent.setShowTitle(true); 43 | customTabsIntent.setToolbarColor(XposedApp.getColor(activity)); 44 | customTabsIntent.build().launchUrl(activity, uri); 45 | } 46 | 47 | public static void startURL(Activity activity, String url) { 48 | startURL(activity, parseURL(url)); 49 | } 50 | 51 | @AnyThread 52 | public static void showMessage(final @NonNull Context context, final CharSequence message) { 53 | XposedApp.runOnUiThread(new Runnable() { 54 | @Override 55 | public void run() { 56 | new MaterialDialog.Builder(context) 57 | .content(message) 58 | .positiveText(android.R.string.ok) 59 | .show(); 60 | } 61 | }); 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/ThemeUtil.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources.Theme; 5 | import android.content.res.TypedArray; 6 | 7 | import de.robv.android.xposed.installer.R; 8 | import de.robv.android.xposed.installer.XposedApp; 9 | import de.robv.android.xposed.installer.XposedBaseActivity; 10 | 11 | public final class ThemeUtil { 12 | private static int[] THEMES = new int[]{ 13 | R.style.Theme_XposedInstaller_Light, 14 | R.style.Theme_XposedInstaller_Dark, 15 | R.style.Theme_XposedInstaller_Dark_Black,}; 16 | 17 | private ThemeUtil() { 18 | } 19 | 20 | public static int getSelectTheme() { 21 | int theme = XposedApp.getPreferences().getInt("theme", 0); 22 | return (theme >= 0 && theme < THEMES.length) ? theme : 0; 23 | } 24 | 25 | public static void setTheme(XposedBaseActivity activity) { 26 | activity.mTheme = getSelectTheme(); 27 | activity.setTheme(THEMES[activity.mTheme]); 28 | } 29 | 30 | public static void reloadTheme(XposedBaseActivity activity) { 31 | int theme = getSelectTheme(); 32 | if (theme != activity.mTheme) 33 | activity.recreate(); 34 | } 35 | 36 | public static int getThemeColor(Context context, int id) { 37 | Theme theme = context.getTheme(); 38 | TypedArray a = theme.obtainStyledAttributes(new int[]{id}); 39 | int result = a.getColor(0, 0); 40 | a.recycle(); 41 | return result; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/chrome/CustomTabsURLSpan.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.chrome; 2 | 3 | import android.app.Activity; 4 | import android.text.style.URLSpan; 5 | import android.view.View; 6 | 7 | import de.robv.android.xposed.installer.util.NavUtil; 8 | 9 | /** 10 | * Created by Nikola D. on 12/23/2015. 11 | */ 12 | public class CustomTabsURLSpan extends URLSpan { 13 | 14 | private Activity activity; 15 | 16 | public CustomTabsURLSpan(Activity activity, String url) { 17 | super(url); 18 | this.activity = activity; 19 | } 20 | 21 | @Override 22 | public void onClick(View widget) { 23 | String url = getURL(); 24 | NavUtil.startURL(activity, url); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/chrome/LinkTransformationMethod.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.chrome; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Rect; 5 | import android.text.Spannable; 6 | import android.text.Spanned; 7 | import android.text.method.TransformationMethod; 8 | import android.text.style.URLSpan; 9 | import android.text.util.Linkify; 10 | import android.view.View; 11 | import android.widget.TextView; 12 | 13 | /** 14 | * Created by Nikola D. on 12/23/2015. 15 | */ 16 | public class LinkTransformationMethod implements TransformationMethod { 17 | 18 | private Activity activity; 19 | 20 | public LinkTransformationMethod(Activity activity) { 21 | this.activity = activity; 22 | } 23 | 24 | @Override 25 | public CharSequence getTransformation(CharSequence source, View view) { 26 | if (view instanceof TextView) { 27 | TextView textView = (TextView) view; 28 | Linkify.addLinks(textView, Linkify.WEB_URLS); 29 | if (textView.getText() == null || !(textView.getText() instanceof Spannable)) { 30 | return source; 31 | } 32 | Spannable text = (Spannable) textView.getText(); 33 | URLSpan[] spans = text.getSpans(0, textView.length(), URLSpan.class); 34 | for (int i = spans.length - 1; i >= 0; i--) { 35 | URLSpan oldSpan = spans[i]; 36 | int start = text.getSpanStart(oldSpan); 37 | int end = text.getSpanEnd(oldSpan); 38 | String url = oldSpan.getURL(); 39 | text.removeSpan(oldSpan); 40 | text.setSpan(new CustomTabsURLSpan(activity, url), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 41 | } 42 | return text; 43 | } 44 | return source; 45 | } 46 | 47 | @Override 48 | public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect) { 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/chrome/ServiceConnection.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.chrome; 2 | 3 | import android.content.ComponentName; 4 | import android.support.customtabs.CustomTabsClient; 5 | import android.support.customtabs.CustomTabsServiceConnection; 6 | 7 | import java.lang.ref.WeakReference; 8 | 9 | /** 10 | * Implementation for the CustomTabsServiceConnection that avoids leaking the 11 | * ServiceConnectionCallback 12 | */ 13 | public class ServiceConnection extends CustomTabsServiceConnection { 14 | // A weak reference to the ServiceConnectionCallback to avoid leaking it. 15 | private WeakReference mConnectionCallback; 16 | 17 | public ServiceConnection(ServiceConnectionCallback connectionCallback) { 18 | mConnectionCallback = new WeakReference<>(connectionCallback); 19 | } 20 | 21 | @Override 22 | public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) { 23 | ServiceConnectionCallback connectionCallback = mConnectionCallback.get(); 24 | if (connectionCallback != null) 25 | connectionCallback.onServiceConnected(client); 26 | } 27 | 28 | @Override 29 | public void onServiceDisconnected(ComponentName name) { 30 | ServiceConnectionCallback connectionCallback = mConnectionCallback.get(); 31 | if (connectionCallback != null) 32 | connectionCallback.onServiceDisconnected(); 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/chrome/ServiceConnectionCallback.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.chrome; 2 | 3 | import android.support.customtabs.CustomTabsClient; 4 | 5 | /** 6 | * Callback for events when connecting and disconnecting from Custom Tabs 7 | * Service. 8 | */ 9 | public interface ServiceConnectionCallback { 10 | /** 11 | * Called when the service is connected. 12 | * 13 | * @param client a CustomTabsClient 14 | */ 15 | void onServiceConnected(CustomTabsClient client); 16 | 17 | /** 18 | * Called when the service is disconnected. 19 | */ 20 | void onServiceDisconnected(); 21 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/json/JSONUtils.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.json; 2 | 3 | import android.os.Build; 4 | 5 | import com.google.gson.Gson; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | import java.net.HttpURLConnection; 11 | import java.net.URL; 12 | import java.util.List; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | public class JSONUtils { 17 | 18 | public static final String JSON_LINK = "https://raw.githubusercontent.com/DVDAndroid/XposedInstaller/material/app/xposed_list_v2.json"; 19 | 20 | public static String getFileContent(String url) throws IOException { 21 | HttpURLConnection c = (HttpURLConnection) new URL(url).openConnection(); 22 | c.setRequestMethod("GET"); 23 | c.setInstanceFollowRedirects(false); 24 | c.setDoOutput(false); 25 | c.connect(); 26 | 27 | BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); 28 | StringBuilder sb = new StringBuilder(); 29 | String line; 30 | while ((line = br.readLine()) != null) { 31 | sb.append(line); 32 | } 33 | br.close(); 34 | 35 | return sb.toString(); 36 | } 37 | 38 | private static String getLatestVersion() throws IOException { 39 | String site = getFileContent("http://dl-xda.xposed.info/framework/sdk" + Build.VERSION.SDK_INT + "/arm/"); 40 | 41 | Pattern pattern = Pattern.compile("(href=\")([^\\?\"]*)\\.zip"); 42 | Matcher matcher = pattern.matcher(site); 43 | String last = ""; 44 | while (matcher.find()) { 45 | if (matcher.group().contains("test")) continue; 46 | last = matcher.group(); 47 | } 48 | last = last.replace("href=\"", ""); 49 | String[] file = last.split("-"); 50 | 51 | return file[1].replace("v", ""); 52 | } 53 | 54 | public static String listZip() { 55 | String latest; 56 | try { 57 | latest = getLatestVersion(); 58 | } catch (IOException e) { 59 | // Got 404 response; no official Xposed zips available 60 | return ""; 61 | } 62 | 63 | String newJson = ",\"" + Build.VERSION.SDK_INT + "\": ["; 64 | String[] arch = new String[]{ 65 | "arm", 66 | "arm64", 67 | "x86" 68 | }; 69 | 70 | for (String a : arch) { 71 | newJson += installerToString(latest, a) + ","; 72 | } 73 | 74 | newJson = newJson.substring(0, newJson.length() - 1); 75 | newJson += "]"; 76 | 77 | return newJson; 78 | } 79 | 80 | private static String installerToString(String latest, String architecture) { 81 | String filename = "xposed-v" + latest + "-sdk" + Build.VERSION.SDK_INT + "-" + architecture; 82 | 83 | XposedZip installer = new XposedZip(); 84 | installer.name = filename; 85 | installer.version = latest; 86 | installer.architecture = architecture; 87 | installer.link = "http://dl-xda.xposed.info/framework/sdk" + Build.VERSION.SDK_INT + "/" + architecture + "/" + filename + ".zip"; 88 | 89 | return new Gson().toJson(installer); 90 | } 91 | 92 | public class XposedJson { 93 | public List tabs; 94 | public ApkRelease apk; 95 | } 96 | 97 | public class ApkRelease { 98 | public String version; 99 | public String changelog; 100 | public String link; 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/json/XposedTab.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.json; 2 | 3 | 4 | import android.os.Build; 5 | import android.os.Parcel; 6 | import android.os.Parcelable; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | 12 | public class XposedTab implements Parcelable { 13 | 14 | public static final Creator CREATOR = new Creator() { 15 | @Override 16 | public XposedTab createFromParcel(Parcel in) { 17 | return new XposedTab(in); 18 | } 19 | 20 | @Override 21 | public XposedTab[] newArray(int size) { 22 | return new XposedTab[size]; 23 | } 24 | }; 25 | 26 | public String name = ""; 27 | public List sdks = new ArrayList<>(); 28 | public String author = ""; 29 | public boolean stable = true; 30 | 31 | public HashMap compatibility = new HashMap<>(); 32 | public HashMap incompatibility = new HashMap<>(); 33 | public HashMap support = new HashMap<>(); 34 | public HashMap> installers = new HashMap<>(); 35 | public List uninstallers = new ArrayList<>(); 36 | 37 | public XposedTab() { } 38 | 39 | protected XposedTab(Parcel in) { 40 | name = in.readString(); 41 | author = in.readString(); 42 | stable = in.readByte() != 0; 43 | } 44 | 45 | public String getCompatibility() { 46 | if (compatibility == null) return ""; 47 | return compatibility.get(Integer.toString(Build.VERSION.SDK_INT)); 48 | } 49 | 50 | public String getIncompatibility() { 51 | if (incompatibility == null) return ""; 52 | return incompatibility.get(Integer.toString(Build.VERSION.SDK_INT)); 53 | } 54 | 55 | public String getSupport() { 56 | if (support == null) return ""; 57 | return support.get(Integer.toString(Build.VERSION.SDK_INT)); 58 | } 59 | 60 | public List getInstallers() { 61 | if (support == null) return new ArrayList<>(); 62 | return installers.get(Integer.toString(Build.VERSION.SDK_INT)); 63 | } 64 | 65 | @Override 66 | public int describeContents() { 67 | return 0; 68 | } 69 | 70 | @Override 71 | public void writeToParcel(Parcel dest, int flags) { 72 | dest.writeString(name); 73 | dest.writeString(author); 74 | dest.writeByte((byte) (stable ? 1 : 0)); 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/util/json/XposedZip.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.util.json; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.TextView; 12 | 13 | import java.util.List; 14 | 15 | public class XposedZip { 16 | 17 | public String name; 18 | public String link; 19 | public String version; 20 | public String architecture; 21 | 22 | public static class MyAdapter extends ArrayAdapter { 23 | 24 | private final Context context; 25 | List list; 26 | 27 | public MyAdapter(Context context, List objects) { 28 | super(context, android.R.layout.simple_dropdown_item_1line, objects); 29 | this.context = context; 30 | this.list = objects; 31 | } 32 | 33 | @NonNull 34 | @Override 35 | public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 36 | return getMyView(parent, position); 37 | } 38 | 39 | @Override 40 | public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 41 | return getMyView(parent, position); 42 | } 43 | 44 | private View getMyView(ViewGroup parent, int position) { 45 | View row; 46 | ItemHolder holder = new ItemHolder(); 47 | 48 | LayoutInflater inflater = ((Activity) context).getLayoutInflater(); 49 | row = inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false); 50 | 51 | holder.name = (TextView) row.findViewById(android.R.id.text1); 52 | 53 | row.setTag(holder); 54 | 55 | holder.name.setText(list.get(position).name); 56 | return row; 57 | } 58 | 59 | private class ItemHolder { 60 | TextView name; 61 | } 62 | 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/widget/IconListPreference.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.widget; 2 | 3 | /* 4 | * Copyright (C) 2013 The Android Open Source Project 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.annotation.SuppressLint; 20 | import android.app.Activity; 21 | import android.app.AlertDialog.Builder; 22 | import android.content.Context; 23 | import android.content.res.TypedArray; 24 | import android.graphics.drawable.Drawable; 25 | import android.preference.ListPreference; 26 | import android.util.AttributeSet; 27 | import android.view.LayoutInflater; 28 | import android.view.View; 29 | import android.view.ViewGroup; 30 | import android.widget.ArrayAdapter; 31 | import android.widget.CheckedTextView; 32 | import android.widget.ImageView; 33 | import android.widget.ListAdapter; 34 | 35 | import java.util.ArrayList; 36 | import java.util.List; 37 | 38 | import de.robv.android.xposed.installer.R; 39 | 40 | public class IconListPreference extends ListPreference { 41 | 42 | private List mEntryDrawables = new ArrayList<>(); 43 | 44 | public IconListPreference(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | 47 | TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.IconListPreference, 0, 0); 48 | 49 | CharSequence[] drawables; 50 | 51 | try { 52 | drawables = a.getTextArray(R.styleable.IconListPreference_icons); 53 | } finally { 54 | a.recycle(); 55 | } 56 | 57 | for (CharSequence drawable : drawables) { 58 | int resId = context.getResources().getIdentifier(drawable.toString(), "mipmap", context.getPackageName()); 59 | 60 | Drawable d = context.getResources().getDrawable(resId); 61 | 62 | mEntryDrawables.add(d); 63 | } 64 | 65 | setWidgetLayoutResource(R.layout.color_icon_preview); 66 | } 67 | 68 | protected ListAdapter createListAdapter() { 69 | final String selectedValue = getValue(); 70 | int selectedIndex = findIndexOfValue(selectedValue); 71 | return new AppArrayAdapter(getContext(), R.layout.icon_preference_item, getEntries(), mEntryDrawables, selectedIndex); 72 | } 73 | 74 | @Override 75 | protected void onBindView(View view) { 76 | super.onBindView(view); 77 | 78 | String selectedValue = getValue(); 79 | int selectedIndex = findIndexOfValue(selectedValue); 80 | 81 | Drawable drawable = mEntryDrawables.get(selectedIndex); 82 | 83 | ((ImageView) view.findViewById(R.id.preview)).setImageDrawable(drawable); 84 | } 85 | 86 | @Override 87 | protected void onPrepareDialogBuilder(Builder builder) { 88 | builder.setAdapter(createListAdapter(), this); 89 | super.onPrepareDialogBuilder(builder); 90 | } 91 | 92 | public class AppArrayAdapter extends ArrayAdapter { 93 | private List mImageDrawables = null; 94 | private int mSelectedIndex = 0; 95 | 96 | public AppArrayAdapter(Context context, int textViewResourceId, 97 | CharSequence[] objects, List imageDrawables, 98 | int selectedIndex) { 99 | super(context, textViewResourceId, objects); 100 | mSelectedIndex = selectedIndex; 101 | mImageDrawables = imageDrawables; 102 | } 103 | 104 | @Override 105 | @SuppressLint("ViewHolder") 106 | public View getView(int position, View convertView, ViewGroup parent) { 107 | LayoutInflater inflater = ((Activity) getContext()).getLayoutInflater(); 108 | View view = inflater.inflate(R.layout.icon_preference_item, parent, false); 109 | CheckedTextView textView = view.findViewById(R.id.label); 110 | textView.setText(getItem(position)); 111 | textView.setChecked(position == mSelectedIndex); 112 | 113 | ImageView imageView = view.findViewById(R.id.icon); 114 | imageView.setImageDrawable(mImageDrawables.get(position)); 115 | return view; 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/widget/IntegerListPreference.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.widget; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.util.AttributeSet; 6 | 7 | import com.afollestad.materialdialogs.prefs.MaterialListPreference; 8 | 9 | public class IntegerListPreference extends MaterialListPreference { 10 | public IntegerListPreference(Context context) { 11 | super(context); 12 | } 13 | 14 | public IntegerListPreference(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | public static int getIntValue(String value) { 19 | if (value == null) 20 | return 0; 21 | 22 | return (int) ((value.startsWith("0x")) 23 | ? Long.parseLong(value.substring(2), 16) 24 | : Long.parseLong(value)); 25 | } 26 | 27 | @Override 28 | public void setValue(String value) { 29 | super.setValue(value); 30 | notifyChanged(); 31 | } 32 | 33 | @Override 34 | protected boolean persistString(String value) { 35 | return value != null && persistInt(getIntValue(value)); 36 | 37 | } 38 | 39 | @Override 40 | protected String getPersistedString(String defaultReturnValue) { 41 | SharedPreferences pref = getPreferenceManager().getSharedPreferences(); 42 | String key = getKey(); 43 | if (!shouldPersist() || !pref.contains(key)) 44 | return defaultReturnValue; 45 | 46 | return String.valueOf(pref.getInt(key, 0)); 47 | } 48 | 49 | @Override 50 | public int findIndexOfValue(String value) { 51 | CharSequence[] entryValues = getEntryValues(); 52 | int intValue = getIntValue(value); 53 | if (value != null && entryValues != null) { 54 | for (int i = entryValues.length - 1; i >= 0; i--) { 55 | if (getIntValue(entryValues[i].toString()) == intValue) { 56 | return i; 57 | } 58 | } 59 | } 60 | return -1; 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/de/robv/android/xposed/installer/widget/ListPreferenceSummaryFix.java: -------------------------------------------------------------------------------- 1 | package de.robv.android.xposed.installer.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | import com.afollestad.materialdialogs.prefs.MaterialListPreference; 7 | 8 | public class ListPreferenceSummaryFix extends MaterialListPreference { 9 | public ListPreferenceSummaryFix(Context context) { 10 | super(context); 11 | } 12 | 13 | public ListPreferenceSummaryFix(Context context, AttributeSet attrs) { 14 | super(context, attrs); 15 | } 16 | 17 | @Override 18 | public void setValue(String value) { 19 | super.setValue(value); 20 | notifyChanged(); 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_action_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_action_thumb_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_action_thumb_up.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_android.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_bookmark.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_bookmark_outline.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_check_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_chip.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_close.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_description.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_donate.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_error.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_github.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_help.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_history.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_info.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_language.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_manufacturer.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_refresh.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_search.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_menu_sort.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_about.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_downloads.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_install.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_logs.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_modules.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_settings.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_nav_support.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_no_connection.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 14 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_no_image.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_notification.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_person.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_save.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_scroll_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_scroll_top.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_send.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_update.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_warning.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_warning_grey.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-anydpi/ic_xda.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_normal_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_normal_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_normal_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_pressed_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_pressed_dark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_card_pressed_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_flash.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_verified.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/toolbar_shadow.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v23/list_item_download.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 18 | 19 | 27 | 28 | 36 | 37 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_container.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_download_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 19 | 20 | 29 | 30 | 31 | 32 | 38 | 39 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_download_details_not_found.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 22 | 23 |