From 65161fa6420ca1d9d93cc6dfa9890849ed17dbc1 Mon Sep 17 00:00:00 2001 From: DVDAndroid Date: Sat, 15 Aug 2015 11:05:26 +0200 Subject: [PATCH 001/547] initial commit --- .gitignore | 26 +- app/lint.xml | 6 +- app/src/main/AndroidManifest.xml | 79 +- .../xposed/installer/AboutActivity.java | 24 +- .../installer/DownloadDetailsActivity.java | 59 +- .../installer/DownloadDetailsFragment.java | 29 +- .../DownloadDetailsSettingsFragment.java | 22 +- .../DownloadDetailsVersionsFragment.java | 223 +++-- .../xposed/installer/DownloadFragment.java | 191 +++-- .../xposed/installer/DownloadReceiver.java | 4 +- .../xposed/installer/InstallerFragment.java | 769 ++++++++++-------- .../xposed/installer/LogsFragment.java | 100 ++- .../xposed/installer/ModulesFragment.java | 178 ++-- .../installer/PackageChangeReceiver.java | 29 +- .../xposed/installer/SettingsActivity.java | 211 ++--- .../xposed/installer/SupportActivity.java | 24 +- .../xposed/installer/WelcomeActivity.java | 41 +- .../android/xposed/installer/XposedApp.java | 130 +-- .../android/xposed/installer/repo/Module.java | 12 +- .../xposed/installer/repo/ModuleVersion.java | 3 +- .../xposed/installer/repo/ReleaseType.java | 22 +- .../android/xposed/installer/repo/RepoDb.java | 398 +++++---- .../installer/repo/RepoDbDefinitions.java | 352 ++++---- .../xposed/installer/repo/RepoParser.java | 105 +-- .../xposed/installer/repo/Repository.java | 4 +- .../xposed/installer/util/AssetUtil.java | 61 +- .../xposed/installer/util/DownloadsUtil.java | 249 +++--- .../xposed/installer/util/HashUtil.java | 5 +- .../xposed/installer/util/ModuleUtil.java | 141 ++-- .../xposed/installer/util/NavUtil.java | 19 +- .../installer/util/NotificationUtil.java | 138 ++-- .../util/PrefixedSharedPreferences.java | 33 +- .../xposed/installer/util/RepoLoader.java | 88 +- .../xposed/installer/util/RootUtil.java | 36 +- .../xposed/installer/util/ThemeUtil.java | 15 +- .../android/xposed/installer/util/UIUtil.java | 6 +- .../xposed/installer/widget/DownloadView.java | 162 ++-- .../widget/IntegerListPreference.java | 18 +- app/src/main/res/anim/slide_in_left.xml | 6 +- app/src/main/res/anim/slide_in_right.xml | 6 +- app/src/main/res/anim/slide_out_left.xml | 4 +- app/src/main/res/anim/slide_out_right.xml | 6 +- .../res/drawable/background_card_black.xml | 8 +- .../res/drawable/background_card_dark.xml | 8 +- .../res/drawable/background_card_light.xml | 8 +- .../drawable/background_card_normal_black.xml | 13 +- .../drawable/background_card_normal_dark.xml | 13 +- .../drawable/background_card_normal_light.xml | 13 +- .../background_card_pressed_black.xml | 25 +- .../drawable/background_card_pressed_dark.xml | 25 +- .../background_card_pressed_light.xml | 25 +- .../main/res/layout/activity_container.xml | 16 +- .../res/layout/activity_download_details.xml | 20 +- .../activity_download_details_not_found.xml | 18 +- app/src/main/res/layout/activity_welcome.xml | 76 +- .../res/layout/dialog_install_warning.xml | 12 +- app/src/main/res/layout/download_details.xml | 18 +- app/src/main/res/layout/download_moreinfo.xml | 23 +- app/src/main/res/layout/download_view.xml | 17 +- .../main/res/layout/list_item_download.xml | 17 +- app/src/main/res/layout/list_item_module.xml | 54 +- app/src/main/res/layout/list_item_version.xml | 39 +- app/src/main/res/layout/list_item_welcome.xml | 26 +- .../layout/list_sticky_header_download.xml | 18 +- app/src/main/res/layout/tab_about.xml | 30 +- app/src/main/res/layout/tab_downloader.xml | 16 +- app/src/main/res/layout/tab_installer.xml | 44 +- app/src/main/res/layout/tab_logs.xml | 10 +- app/src/main/res/layout/tab_support.xml | 28 +- .../res/layout/xposed_not_active_note.xml | 33 +- .../main/res/menu/context_menu_modules.xml | 4 +- app/src/main/res/menu/drawer.xml | 5 +- app/src/main/res/menu/menu_download.xml | 14 +- .../main/res/menu/menu_download_details.xml | 2 +- app/src/main/res/menu/menu_logs.xml | 18 +- app/src/main/res/values-v21/styles.xml | 6 +- app/src/main/res/values/attrs.xml | 14 +- app/src/main/res/values/styles.xml | 6 +- app/src/main/res/xml/module_prefs.xml | 4 +- app/src/main/res/xml/prefs.xml | 60 +- 80 files changed, 2666 insertions(+), 2154 deletions(-) diff --git a/.gitignore b/.gitignore index b3f9dc9c7..e3ae87a64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,11 @@ -# Built application files *.apk *.ap_ *.iml - -# Files for the Dalvik VM *.dex - -# Java class files *.class - -# Generated files -bin/ -gen/ - -# User-specific stuff: .idea/ - -# Gradle files .gradle/ build/ - -# Local configuration file (sdk path, etc) local.properties - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ \ No newline at end of file +app/lint.xml +app/proguard-project.txt \ No newline at end of file diff --git a/app/lint.xml b/app/lint.xml index 38567987d..b8e8d4ccc 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -1,10 +1,10 @@ - - + + - + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 63b1f1a06..778b27c61 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,77 +1,86 @@ - + + tools:ignore="OldTargetApi"/> - - - + + + + android:theme="@style/Theme.XposedInstaller.Light"> + android:exported="true" + android:label="@string/app_name"> - - + + + android:exported="true"> - - - + + + - - - - + + + + + - + - + - + - + - - - - + + + + + - + android:permission="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS"> - + - + diff --git a/app/src/main/java/de/robv/android/xposed/installer/AboutActivity.java b/app/src/main/java/de/robv/android/xposed/installer/AboutActivity.java index f79484458..3193b6adf 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/AboutActivity.java +++ b/app/src/main/java/de/robv/android/xposed/installer/AboutActivity.java @@ -22,7 +22,8 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_container); if (UIUtil.isLollipop()) { - this.getWindow().setStatusBarColor(this.getResources().getColor(R.color.colorPrimaryDark)); + this.getWindow().setStatusBarColor( + this.getResources().getColor(R.color.colorPrimaryDark)); } Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); @@ -43,8 +44,7 @@ public void onClick(View view) { if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() - .add(R.id.container, new AboutFragment()) - .commit(); + .add(R.id.container, new AboutFragment()).commit(); } } @@ -55,26 +55,32 @@ public void onCreate(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { View v = inflater.inflate(R.layout.tab_about, container, false); try { String packageName = getActivity().getPackageName(); - String version = getActivity().getPackageManager().getPackageInfo(packageName, 0).versionName; + String version = getActivity().getPackageManager() + .getPackageInfo(packageName, 0).versionName; ((TextView) v.findViewById(R.id.version)).setText(version); } catch (NameNotFoundException e) { // should not happen } - ((TextView) v.findViewById(R.id.about_developers)).setMovementMethod(LinkMovementMethod.getInstance()); - ((TextView) v.findViewById(R.id.about_libraries)).setMovementMethod(LinkMovementMethod.getInstance()); + ((TextView) v.findViewById(R.id.about_developers)) + .setMovementMethod(LinkMovementMethod.getInstance()); + ((TextView) v.findViewById(R.id.about_libraries)) + .setMovementMethod(LinkMovementMethod.getInstance()); String translator = getResources().getString(R.string.translator); if (translator.isEmpty()) { - v.findViewById(R.id.about_translator_label).setVisibility(View.GONE); + v.findViewById(R.id.about_translator_label) + .setVisibility(View.GONE); v.findViewById(R.id.about_translator).setVisibility(View.GONE); } else { - ((TextView) v.findViewById(R.id.about_translator)).setMovementMethod(LinkMovementMethod.getInstance()); + ((TextView) v.findViewById(R.id.about_translator)) + .setMovementMethod(LinkMovementMethod.getInstance()); } return v; diff --git a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsActivity.java b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsActivity.java index 4c0a831cb..edcba49c7 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsActivity.java +++ b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsActivity.java @@ -1,7 +1,5 @@ package de.robv.android.xposed.installer; -import java.util.List; - import android.net.Uri; import android.os.Bundle; import android.support.design.widget.TabLayout; @@ -17,6 +15,9 @@ import android.view.MenuItem; import android.view.View; import android.widget.TextView; + +import java.util.List; + import de.robv.android.xposed.installer.repo.Module; import de.robv.android.xposed.installer.util.ModuleUtil; import de.robv.android.xposed.installer.util.ModuleUtil.InstalledModule; @@ -26,22 +27,21 @@ import de.robv.android.xposed.installer.util.ThemeUtil; import de.robv.android.xposed.installer.util.UIUtil; +public class DownloadDetailsActivity extends XposedBaseActivity + implements RepoListener, ModuleListener { -public class DownloadDetailsActivity extends XposedBaseActivity implements RepoListener, ModuleListener { - - private ViewPager mPager; - private String mPackageName; + public static final int DOWNLOAD_DESCRIPTION = 0; + public static final int DOWNLOAD_VERSIONS = 1; + public static final int DOWNLOAD_SETTINGS = 2; private static RepoLoader sRepoLoader = RepoLoader.getInstance(); private static ModuleUtil sModuleUtil = ModuleUtil.getInstance(); + private ViewPager mPager; + private String mPackageName; private Module mModule; private InstalledModule mInstalledModule; private Toolbar mToolbar; private TabLayout mTabLayout; - public static final int DOWNLOAD_DESCRIPTION = 0; - public static final int DOWNLOAD_VERSIONS = 1; - public static final int DOWNLOAD_SETTINGS = 2; - @Override public void onCreate(Bundle savedInstanceState) { ThemeUtil.setTheme(this); @@ -59,7 +59,8 @@ public void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_download_details); if (UIUtil.isLollipop()) { - this.getWindow().setStatusBarColor(this.getResources().getColor(R.color.colorPrimaryDark)); + this.getWindow().setStatusBarColor( + this.getResources().getColor(R.color.colorPrimaryDark)); } mToolbar = (Toolbar) findViewById(R.id.toolbar); @@ -83,33 +84,36 @@ public void onClick(View view) { setupTabs(); // Updates available => start on the versions page - if (mInstalledModule != null && mInstalledModule.isUpdate(sRepoLoader.getLatestVersion(mModule))) + if (mInstalledModule != null && mInstalledModule + .isUpdate(sRepoLoader.getLatestVersion(mModule))) mPager.setCurrentItem(DOWNLOAD_VERSIONS); } else { setContentView(R.layout.activity_download_details_not_found); TextView txtMessage = (TextView) findViewById(android.R.id.message); - txtMessage.setText(getResources().getString(R.string.download_details_not_found, mPackageName)); - - findViewById(R.id.reload).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - v.setEnabled(false); - sRepoLoader.triggerReload(true); - } - }); + txtMessage.setText(getResources().getString( + R.string.download_details_not_found, mPackageName)); + + findViewById(R.id.reload) + .setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + v.setEnabled(false); + sRepoLoader.triggerReload(true); + } + }); } } private void setupTabs() { mPager = (ViewPager) findViewById(R.id.download_pager); - mPager.setAdapter(new SwipeFragmentPagerAdapter(getSupportFragmentManager())); + mPager.setAdapter( + new SwipeFragmentPagerAdapter(getSupportFragmentManager())); mTabLayout = (TabLayout) findViewById(R.id.sliding_tabs); mTabLayout.setupWithViewPager(mPager); } - private String getModulePackageName() { Uri uri = getIntent().getData(); if (uri == null) @@ -167,7 +171,8 @@ public void onInstalledModulesReloaded(ModuleUtil moduleUtil) { } @Override - public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, InstalledModule module) { + public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, + String packageName, InstalledModule module) { if (packageName.equals(mPackageName)) reload(); } @@ -190,10 +195,10 @@ public boolean onOptionsItemSelected(MenuItem item) { class SwipeFragmentPagerAdapter extends FragmentPagerAdapter { final int PAGE_COUNT = 3; - private String tabTitles[] = new String[]{getString(R.string.download_details_page_description), + private String tabTitles[] = new String[] { + getString(R.string.download_details_page_description), getString(R.string.download_details_page_versions), - getString(R.string.download_details_page_settings), - }; + getString(R.string.download_details_page_settings), }; public SwipeFragmentPagerAdapter(FragmentManager fm) { super(fm); diff --git a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsFragment.java b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsFragment.java index dfbeedf57..e5f1d260c 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsFragment.java @@ -1,15 +1,16 @@ package de.robv.android.xposed.installer; import android.app.Activity; -import android.support.v4.app.Fragment; import android.net.Uri; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.text.method.LinkMovementMethod; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + import de.robv.android.xposed.installer.repo.Module; import de.robv.android.xposed.installer.repo.RepoParser; import de.robv.android.xposed.installer.util.NavUtil; @@ -24,12 +25,14 @@ public void onAttach(Activity activity) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { final Module module = mActivity.getModule(); if (module == null) return null; - final View view = inflater.inflate(R.layout.download_details, container, false); + final View view = inflater.inflate(R.layout.download_details, container, + false); TextView title = (TextView) view.findViewById(R.id.download_title); title.setText(module.name); @@ -40,10 +43,12 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa else author.setText(R.string.download_unknown_author); - TextView description = (TextView) view.findViewById(R.id.download_description); + TextView description = (TextView) view + .findViewById(R.id.download_description); if (module.description != null) { if (module.descriptionIsHtml) { - description.setText(RepoParser.parseSimpleHtml(module.description)); + description.setText( + RepoParser.parseSimpleHtml(module.description)); description.setMovementMethod(LinkMovementMethod.getInstance()); } else { description.setText(module.description); @@ -52,11 +57,15 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa description.setVisibility(View.GONE); } - ViewGroup moreInfoContainer = (ViewGroup) view.findViewById(R.id.download_moreinfo_container); - for (Pair moreInfoEntry : module.moreInfo) { - View moreInfoView = inflater.inflate(R.layout.download_moreinfo, moreInfoContainer, false); - TextView txtTitle = (TextView) moreInfoView.findViewById(android.R.id.title); - TextView txtValue = (TextView) moreInfoView.findViewById(android.R.id.message); + ViewGroup moreInfoContainer = (ViewGroup) view + .findViewById(R.id.download_moreinfo_container); + for (Pair moreInfoEntry : module.moreInfo) { + View moreInfoView = inflater.inflate(R.layout.download_moreinfo, + moreInfoContainer, false); + TextView txtTitle = (TextView) moreInfoView + .findViewById(android.R.id.title); + TextView txtValue = (TextView) moreInfoView + .findViewById(android.R.id.message); txtTitle.setText(moreInfoEntry.first + ":"); txtValue.setText(moreInfoEntry.second); diff --git a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsSettingsFragment.java b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsSettingsFragment.java index 28a05c21f..2271f439a 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsSettingsFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsSettingsFragment.java @@ -5,7 +5,9 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceManager; + import com.github.machinarius.preferencefragment.PreferenceFragment; + import de.robv.android.xposed.installer.repo.Module; import de.robv.android.xposed.installer.util.PrefixedSharedPreferences; import de.robv.android.xposed.installer.util.RepoLoader; @@ -31,15 +33,19 @@ public void onCreate(Bundle savedInstanceState) { PreferenceManager prefManager = getPreferenceManager(); prefManager.setSharedPreferencesName("module_settings"); - PrefixedSharedPreferences.injectToPreferenceManager(prefManager, module.packageName); + PrefixedSharedPreferences.injectToPreferenceManager(prefManager, + module.packageName); addPreferencesFromResource(R.xml.module_prefs); - findPreference("release_type").setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - RepoLoader.getInstance().setReleaseTypeLocal(packageName, (String) newValue); - return true; - } - }); + findPreference("release_type").setOnPreferenceChangeListener( + new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, + Object newValue) { + RepoLoader.getInstance().setReleaseTypeLocal( + packageName, (String) newValue); + return true; + } + }); } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsVersionsFragment.java b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsVersionsFragment.java index d0104dc1b..e88133402 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsVersionsFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/DownloadDetailsVersionsFragment.java @@ -1,9 +1,5 @@ package de.robv.android.xposed.installer; -import java.io.File; -import java.text.DateFormat; -import java.util.Date; - import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -21,6 +17,11 @@ import android.widget.ArrayAdapter; import android.widget.TextView; import android.widget.Toast; + +import java.io.File; +import java.text.DateFormat; +import java.util.Date; + import de.robv.android.xposed.installer.repo.Module; import de.robv.android.xposed.installer.repo.ModuleVersion; import de.robv.android.xposed.installer.repo.ReleaseType; @@ -33,8 +34,8 @@ import de.robv.android.xposed.installer.widget.DownloadView; public class DownloadDetailsVersionsFragment extends ListFragment { - private DownloadDetailsActivity mActivity; private static VersionsAdapter sAdapter; + private DownloadDetailsActivity mActivity; @Override public void onAttach(Activity activity) { @@ -58,17 +59,20 @@ public void onActivityCreated(Bundle savedInstanceState) { if (!repoLoader.isVersionShown(module.versions.get(0))) { TextView txtHeader = new TextView(getActivity()); txtHeader.setText(R.string.download_test_version_not_shown); - txtHeader.setTextColor(getResources().getColor(R.color.warning)); + txtHeader + .setTextColor(getResources().getColor(R.color.warning)); txtHeader.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mActivity.gotoPage(DownloadDetailsActivity.DOWNLOAD_SETTINGS); + mActivity.gotoPage( + DownloadDetailsActivity.DOWNLOAD_SETTINGS); } }); getListView().addHeaderView(txtHeader); } - sAdapter = new VersionsAdapter(mActivity, mActivity.getInstalledModule()); + sAdapter = new VersionsAdapter(mActivity, + mActivity.getInstalledModule()); for (ModuleVersion version : module.versions) { if (repoLoader.isVersionShown(version)) sAdapter.add(version); @@ -77,8 +81,10 @@ public void onClick(View v) { } DisplayMetrics metrics = getResources().getDisplayMetrics(); - int sixDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, metrics); - int eightDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); + int sixDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + 6, metrics); + int eightDp = (int) TypedValue + .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); getListView().setDivider(null); getListView().setDividerHeight(sixDp); getListView().setPadding(eightDp, eightDp, eightDp, eightDp); @@ -101,8 +107,83 @@ static class ViewHolder { TextView txtChanges; } + private static class DownloadModuleCallback + implements DownloadsUtil.DownloadFinishedCallback { + private final ModuleVersion moduleVersion; + + public DownloadModuleCallback(ModuleVersion moduleVersion) { + this.moduleVersion = moduleVersion; + } + + @Override + public void onDownloadFinished(Context context, + DownloadsUtil.DownloadInfo info) { + File localFile = new File(info.localFilename); + if (!localFile.isFile()) + return; + + if (moduleVersion.md5sum != null + && !moduleVersion.md5sum.isEmpty()) { + try { + String actualMd5Sum = HashUtil.md5(localFile); + if (!moduleVersion.md5sum.equals(actualMd5Sum)) { + Toast.makeText(context, + context.getString( + R.string.download_md5sum_incorrect, + actualMd5Sum, moduleVersion.md5sum), + Toast.LENGTH_LONG).show(); + DownloadsUtil.removeById(context, info.id); + return; + } + } catch (Exception e) { + Toast.makeText(context, + context.getString( + R.string.download_could_not_read_file, + e.getMessage()), + Toast.LENGTH_LONG).show(); + DownloadsUtil.removeById(context, info.id); + return; + } + } + + PackageManager pm = context.getPackageManager(); + PackageInfo packageInfo = pm + .getPackageArchiveInfo(info.localFilename, 0); + + if (packageInfo == null) { + Toast.makeText(context, R.string.download_no_valid_apk, + Toast.LENGTH_LONG).show(); + DownloadsUtil.removeById(context, info.id); + return; + } + + if (!packageInfo.packageName + .equals(moduleVersion.module.packageName)) { + Toast.makeText(context, + context.getString( + R.string.download_incorrect_package_name, + packageInfo.packageName, + moduleVersion.module.packageName), + Toast.LENGTH_LONG).show(); + DownloadsUtil.removeById(context, info.id); + return; + } + + Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + installIntent.setDataAndType(Uri.fromFile(localFile), + DownloadsUtil.MIME_TYPE_APK); + // installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); + // installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); + installIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, + context.getApplicationInfo().packageName); + context.startActivity(installIntent); + } + } + private class VersionsAdapter extends ArrayAdapter { - private final DateFormat mDateFormatter = DateFormat.getDateInstance(DateFormat.SHORT); + private final DateFormat mDateFormatter = DateFormat + .getDateInstance(DateFormat.SHORT); private final int mColorRelTypeStable; private final int mColorRelTypeOthers; private final int mColorInstalled; @@ -113,47 +194,64 @@ private class VersionsAdapter extends ArrayAdapter { public VersionsAdapter(Context context, InstalledModule installed) { super(context, R.layout.list_item_version); - mColorRelTypeStable = ThemeUtil.getThemeColor(context, android.R.attr.textColorTertiary); + mColorRelTypeStable = ThemeUtil.getThemeColor(context, + android.R.attr.textColorTertiary); mColorRelTypeOthers = getResources().getColor(R.color.warning); - mColorInstalled = ThemeUtil.getThemeColor(context, R.attr.download_status_installed); - mColorUpdateAvailable = getResources().getColor(R.color.download_status_update_available); - mTextInstalled = getString(R.string.download_section_installed) + ":"; - mTextUpdateAvailable = getString(R.string.download_section_update_available) + ":"; - mInstalledVersionCode = (installed != null) ? installed.versionCode : -1; + mColorInstalled = ThemeUtil.getThemeColor(context, + R.attr.download_status_installed); + mColorUpdateAvailable = getResources() + .getColor(R.color.download_status_update_available); + mTextInstalled = getString(R.string.download_section_installed) + + ":"; + mTextUpdateAvailable = getString( + R.string.download_section_update_available) + ":"; + mInstalledVersionCode = (installed != null) ? installed.versionCode + : -1; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (view == null) { - LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.list_item_version, null, true); ViewHolder viewHolder = new ViewHolder(); - viewHolder.txtStatus = (TextView) view.findViewById(R.id.txtStatus); - viewHolder.txtVersion = (TextView) view.findViewById(R.id.txtVersion); - viewHolder.txtRelType = (TextView) view.findViewById(R.id.txtRelType); - viewHolder.txtUploadDate = (TextView) view.findViewById(R.id.txtUploadDate); - viewHolder.downloadView = (DownloadView) view.findViewById(R.id.downloadView); - viewHolder.txtChangesTitle = (TextView) view.findViewById(R.id.txtChangesTitle); - viewHolder.txtChanges = (TextView) view.findViewById(R.id.txtChanges); + viewHolder.txtStatus = (TextView) view + .findViewById(R.id.txtStatus); + viewHolder.txtVersion = (TextView) view + .findViewById(R.id.txtVersion); + viewHolder.txtRelType = (TextView) view + .findViewById(R.id.txtRelType); + viewHolder.txtUploadDate = (TextView) view + .findViewById(R.id.txtUploadDate); + viewHolder.downloadView = (DownloadView) view + .findViewById(R.id.downloadView); + viewHolder.txtChangesTitle = (TextView) view + .findViewById(R.id.txtChangesTitle); + viewHolder.txtChanges = (TextView) view + .findViewById(R.id.txtChanges); view.setTag(viewHolder); } ViewHolder holder = (ViewHolder) view.getTag(); - ModuleVersion item = (ModuleVersion) getItem(position); + ModuleVersion item = getItem(position); holder.txtVersion.setText(item.name); holder.txtRelType.setText(item.relType.getTitleId()); - holder.txtRelType.setTextColor(item.relType == ReleaseType.STABLE ? mColorRelTypeStable : mColorRelTypeOthers); + holder.txtRelType.setTextColor(item.relType == ReleaseType.STABLE + ? mColorRelTypeStable : mColorRelTypeOthers); if (item.uploaded > 0) { - holder.txtUploadDate.setText(mDateFormatter.format(new Date(item.uploaded))); + holder.txtUploadDate.setText( + mDateFormatter.format(new Date(item.uploaded))); holder.txtUploadDate.setVisibility(View.VISIBLE); } else { holder.txtUploadDate.setVisibility(View.GONE); } - if (item.code <= 0 || mInstalledVersionCode <= 0 || item.code < mInstalledVersionCode) { + if (item.code <= 0 || mInstalledVersionCode <= 0 + || item.code < mInstalledVersionCode) { holder.txtStatus.setVisibility(View.GONE); } else if (item.code == mInstalledVersionCode) { holder.txtStatus.setText(mTextInstalled); @@ -167,15 +265,18 @@ public View getView(int position, View convertView, ViewGroup parent) { holder.downloadView.setUrl(item.downloadLink); holder.downloadView.setTitle(mActivity.getModule().name); - holder.downloadView.setDownloadFinishedCallback(new DownloadModuleCallback(item)); + holder.downloadView.setDownloadFinishedCallback( + new DownloadModuleCallback(item)); if (item.changelog != null && !item.changelog.isEmpty()) { holder.txtChangesTitle.setVisibility(View.VISIBLE); holder.txtChanges.setVisibility(View.VISIBLE); if (item.changelogIsHtml) { - holder.txtChanges.setText(RepoParser.parseSimpleHtml(item.changelog)); - holder.txtChanges.setMovementMethod(LinkMovementMethod.getInstance()); + holder.txtChanges.setText( + RepoParser.parseSimpleHtml(item.changelog)); + holder.txtChanges.setMovementMethod( + LinkMovementMethod.getInstance()); } else { holder.txtChanges.setText(item.changelog); holder.txtChanges.setMovementMethod(null); @@ -189,62 +290,4 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - - private static class DownloadModuleCallback implements DownloadsUtil.DownloadFinishedCallback { - private final ModuleVersion moduleVersion; - - public DownloadModuleCallback(ModuleVersion moduleVersion) { - this.moduleVersion = moduleVersion; - } - - @Override - public void onDownloadFinished(Context context, DownloadsUtil.DownloadInfo info) { - File localFile = new File(info.localFilename); - if (!localFile.isFile()) - return; - - if (moduleVersion.md5sum != null && !moduleVersion.md5sum.isEmpty()) { - try { - String actualMd5Sum = HashUtil.md5(localFile); - if (!moduleVersion.md5sum.equals(actualMd5Sum)) { - Toast.makeText(context, context.getString(R.string.download_md5sum_incorrect, - actualMd5Sum, moduleVersion.md5sum), Toast.LENGTH_LONG).show(); - DownloadsUtil.removeById(context, info.id); - return; - } - } catch (Exception e) { - Toast.makeText(context, context.getString(R.string.download_could_not_read_file, - e.getMessage()), Toast.LENGTH_LONG).show(); - DownloadsUtil.removeById(context, info.id); - return; - } - } - - PackageManager pm = context.getPackageManager(); - PackageInfo packageInfo = pm.getPackageArchiveInfo(info.localFilename, 0); - - if (packageInfo == null) { - Toast.makeText(context, R.string.download_no_valid_apk, Toast.LENGTH_LONG).show(); - DownloadsUtil.removeById(context, info.id); - return; - } - - if (!packageInfo.packageName.equals(moduleVersion.module.packageName)) { - Toast.makeText(context, - context.getString(R.string.download_incorrect_package_name, - packageInfo.packageName, moduleVersion.module.packageName), - Toast.LENGTH_LONG).show(); - DownloadsUtil.removeById(context, info.id); - return; - } - - Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); - installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - installIntent.setDataAndType(Uri.fromFile(localFile), DownloadsUtil.MIME_TYPE_APK); - //installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); - //installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); - installIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, context.getApplicationInfo().packageName); - context.startActivity(installIntent); - } - } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/DownloadFragment.java b/app/src/main/java/de/robv/android/xposed/installer/DownloadFragment.java index e9da1d7a1..116db34ce 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/DownloadFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/DownloadFragment.java @@ -1,10 +1,6 @@ package de.robv.android.xposed.installer; -import java.text.DateFormat; -import java.util.Date; - import android.app.AlertDialog; -import android.support.v4.app.Fragment; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; @@ -14,6 +10,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.SearchView; import android.view.KeyEvent; @@ -29,8 +26,11 @@ import android.widget.FilterQueryProvider; import android.widget.TextView; -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; +import java.text.DateFormat; +import java.util.Date; + import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; +import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import de.robv.android.xposed.installer.repo.RepoDb; import de.robv.android.xposed.installer.repo.RepoDbDefinitions.OverviewColumnsIndexes; @@ -42,7 +42,8 @@ import de.robv.android.xposed.installer.util.RepoLoader.RepoListener; import de.robv.android.xposed.installer.util.ThemeUtil; -public class DownloadFragment extends Fragment implements RepoListener, ModuleListener { +public class DownloadFragment extends Fragment + implements RepoListener, ModuleListener { private SharedPreferences mPref; private DownloadsAdapter mAdapter; private String mFilterText; @@ -61,14 +62,17 @@ public void onCreate(Bundle savedInstanceState) { mAdapter.setFilterQueryProvider(new FilterQueryProvider() { @Override public Cursor runQuery(CharSequence constraint) { - // TODO Instead of this workaround, show a "downloads disabled" message + // TODO Instead of this workaround, show a "downloads disabled" + // message if (XposedApp.getInstance().areDownloadsEnabled()) - return RepoDb.queryModuleOverview(mSortingOrder, constraint); + return RepoDb.queryModuleOverview(mSortingOrder, + constraint); else return null; } }); - mSortingOrder = mPref.getInt("download_sorting_order", RepoDb.SORT_STATUS); + mSortingOrder = mPref.getInt("download_sorting_order", + RepoDb.SORT_STATUS); setHasOptionsMenu(true); } @@ -78,9 +82,11 @@ public void onActivityCreated(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { View v = inflater.inflate(R.layout.tab_downloader, container, false); - StickyListHeadersListView lv = (StickyListHeadersListView) v.findViewById(R.id.listModules); + StickyListHeadersListView lv = (StickyListHeadersListView) v + .findViewById(R.id.listModules); mRepoLoader.addListener(this, true); mModuleUtil.addListener(this); @@ -88,12 +94,16 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa lv.setOnItemClickListener(new OnItemClickListener() { @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { + public void onItemClick(AdapterView parent, View view, + int position, long id) { Cursor cursor = (Cursor) mAdapter.getItem(position); - String packageName = cursor.getString(OverviewColumnsIndexes.PKGNAME); + String packageName = cursor + .getString(OverviewColumnsIndexes.PKGNAME); - Intent detailsIntent = new Intent(getActivity(), DownloadDetailsActivity.class); - detailsIntent.setData(Uri.fromParts("package", packageName, null)); + Intent detailsIntent = new Intent(getActivity(), + DownloadDetailsActivity.class); + detailsIntent + .setData(Uri.fromParts("package", packageName, null)); detailsIntent.putExtra(NavUtil.FINISH_ON_UP_NAVIGATION, true); startActivity(detailsIntent); NavUtil.setTransitionSlideEnter(getActivity()); @@ -103,7 +113,8 @@ public void onItemClick(AdapterView parent, View view, int position, long id) @Override public boolean onKey(View v, int keyCode, KeyEvent event) { // Expand the search view when the SEARCH key is triggered - if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getAction() == KeyEvent.ACTION_UP + if (keyCode == KeyEvent.KEYCODE_SEARCH + && event.getAction() == KeyEvent.ACTION_UP && (event.getFlags() & KeyEvent.FLAG_CANCELED) == 0) { if (mSearchView != null) mSearchView.setIconified(false); @@ -133,20 +144,21 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { final MenuItem searchItem = menu.findItem(R.id.menu_search); mSearchView = (SearchView) searchItem.getActionView(); mSearchView.setIconifiedByDefault(true); - mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String query) { - setFilter(query); - mSearchView.clearFocus(); - return true; - } + mSearchView + .setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + setFilter(query); + mSearchView.clearFocus(); + return true; + } - @Override - public boolean onQueryTextChange(String newText) { - setFilter(newText); - return true; - } - }); + @Override + public boolean onQueryTextChange(String newText) { + setFilter(newText); + return true; + } + }); MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @Override @@ -178,17 +190,21 @@ public boolean onOptionsItemSelected(MenuItem item) { mRepoLoader.triggerReload(true); return true; case R.id.menu_sort: - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + AlertDialog.Builder builder = new AlertDialog.Builder( + getActivity()); builder.setTitle(R.string.download_sorting_title); - builder.setSingleChoiceItems(R.array.download_sort_order, mSortingOrder, new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - mSortingOrder = which; - mPref.edit().putInt("download_sorting_order", mSortingOrder).commit(); - reloadItems(); - dialog.dismiss(); - } - }); + builder.setSingleChoiceItems(R.array.download_sort_order, + mSortingOrder, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + mSortingOrder = which; + mPref.edit().putInt("download_sorting_order", + mSortingOrder).commit(); + reloadItems(); + dialog.dismiss(); + } + }); builder.show(); return true; } @@ -201,7 +217,8 @@ public void onRepoReloaded(final RepoLoader loader) { } @Override - public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, InstalledModule module) { + public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, + String packageName, InstalledModule module) { reloadItems(); } @@ -210,10 +227,11 @@ public void onInstalledModulesReloaded(ModuleUtil moduleUtil) { reloadItems(); } - - private class DownloadsAdapter extends CursorAdapter implements StickyListHeadersAdapter { + private class DownloadsAdapter extends CursorAdapter + implements StickyListHeadersAdapter { private final Context mContext; - private final DateFormat mDateFormatter = DateFormat.getDateInstance(DateFormat.SHORT); + private final DateFormat mDateFormatter = DateFormat + .getDateInstance(DateFormat.SHORT); private final LayoutInflater mInflater; private String[] sectionHeadersStatus; private String[] sectionHeadersDate; @@ -221,33 +239,37 @@ private class DownloadsAdapter extends CursorAdapter implements StickyListHeader public DownloadsAdapter(Context context) { super(context, null, 0); mContext = context; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mInflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); Resources res = context.getResources(); sectionHeadersStatus = new String[] { - res.getString(R.string.download_section_framework), - res.getString(R.string.download_section_update_available), - res.getString(R.string.download_section_installed), - res.getString(R.string.download_section_not_installed), - }; + res.getString(R.string.download_section_framework), + res.getString(R.string.download_section_update_available), + res.getString(R.string.download_section_installed), + res.getString(R.string.download_section_not_installed), }; sectionHeadersDate = new String[] { - res.getString(R.string.download_section_24h), - res.getString(R.string.download_section_7d), - res.getString(R.string.download_section_30d), - res.getString(R.string.download_section_older) - }; + res.getString(R.string.download_section_24h), + res.getString(R.string.download_section_7d), + res.getString(R.string.download_section_30d), + res.getString(R.string.download_section_older) }; } @Override - public View getHeaderView(int position, View convertView, ViewGroup parent) { + public View getHeaderView(int position, View convertView, + ViewGroup parent) { if (convertView == null) { - convertView = mInflater.inflate(R.layout.list_sticky_header_download, parent, false); + convertView = mInflater.inflate( + R.layout.list_sticky_header_download, parent, false); } long section = getHeaderId(position); - TextView tv = (TextView) convertView.findViewById(android.R.id.title); - tv.setText(mSortingOrder == RepoDb.SORT_STATUS ? sectionHeadersStatus[(int)section] : sectionHeadersDate[(int) section]); + TextView tv = (TextView) convertView + .findViewById(android.R.id.title); + tv.setText(mSortingOrder == RepoDb.SORT_STATUS + ? sectionHeadersStatus[(int) section] + : sectionHeadersDate[(int) section]); return convertView; } @@ -256,12 +278,16 @@ public long getHeaderId(int position) { Cursor cursor = (Cursor) getItem(position); long created = cursor.getLong(OverviewColumnsIndexes.CREATED); long updated = cursor.getLong(OverviewColumnsIndexes.UPDATED); - boolean isFramework = cursor.getInt(OverviewColumnsIndexes.IS_FRAMEWORK) > 0; - boolean isInstalled = cursor.getInt(OverviewColumnsIndexes.IS_INSTALLED) > 0; - boolean hasUpdate = cursor.getInt(OverviewColumnsIndexes.HAS_UPDATE) > 0; + boolean isFramework = cursor + .getInt(OverviewColumnsIndexes.IS_FRAMEWORK) > 0; + boolean isInstalled = cursor + .getInt(OverviewColumnsIndexes.IS_INSTALLED) > 0; + boolean hasUpdate = cursor + .getInt(OverviewColumnsIndexes.HAS_UPDATE) > 0; if (mSortingOrder != RepoDb.SORT_STATUS) { - long timestamp = (mSortingOrder == RepoDb.SORT_UPDATED) ? updated : created; + long timestamp = (mSortingOrder == RepoDb.SORT_UPDATED) + ? updated : created; long age = System.currentTimeMillis() - timestamp; final long mSecsPerDay = 24 * 60 * 60 * 1000L; if (age < mSecsPerDay) @@ -286,34 +312,47 @@ else if (isInstalled) @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.list_item_download, parent, false); + return mInflater.inflate(R.layout.list_item_download, parent, + false); } @Override public void bindView(View view, Context context, Cursor cursor) { String title = cursor.getString(OverviewColumnsIndexes.TITLE); String summary = cursor.getString(OverviewColumnsIndexes.SUMMARY); - String installedVersion = cursor.getString(OverviewColumnsIndexes.INSTALLED_VERSION); - String latestVersion = cursor.getString(OverviewColumnsIndexes.LATEST_VERSION); + String installedVersion = cursor + .getString(OverviewColumnsIndexes.INSTALLED_VERSION); + String latestVersion = cursor + .getString(OverviewColumnsIndexes.LATEST_VERSION); long created = cursor.getLong(OverviewColumnsIndexes.CREATED); long updated = cursor.getLong(OverviewColumnsIndexes.UPDATED); - boolean isInstalled = cursor.getInt(OverviewColumnsIndexes.IS_INSTALLED) > 0; - boolean hasUpdate = cursor.getInt(OverviewColumnsIndexes.HAS_UPDATE) > 0; + boolean isInstalled = cursor + .getInt(OverviewColumnsIndexes.IS_INSTALLED) > 0; + boolean hasUpdate = cursor + .getInt(OverviewColumnsIndexes.HAS_UPDATE) > 0; - TextView txtTitle = (TextView) view.findViewById(android.R.id.text1); + TextView txtTitle = (TextView) view + .findViewById(android.R.id.text1); txtTitle.setText(title); - TextView txtSummary = (TextView) view.findViewById(android.R.id.text2); + TextView txtSummary = (TextView) view + .findViewById(android.R.id.text2); txtSummary.setText(summary); - TextView txtStatus = (TextView) view.findViewById(R.id.downloadStatus); + TextView txtStatus = (TextView) view + .findViewById(R.id.downloadStatus); if (hasUpdate) { - txtStatus.setText(mContext.getString(R.string.download_status_update_available, installedVersion, latestVersion)); - txtStatus.setTextColor(getResources().getColor(R.color.download_status_update_available)); + txtStatus.setText(mContext.getString( + R.string.download_status_update_available, + installedVersion, latestVersion)); + txtStatus.setTextColor(getResources() + .getColor(R.color.download_status_update_available)); txtStatus.setVisibility(View.VISIBLE); } else if (isInstalled) { - txtStatus.setText(mContext.getString(R.string.download_status_installed, installedVersion)); - txtStatus.setTextColor(ThemeUtil.getThemeColor(mContext, R.attr.download_status_installed)); + txtStatus.setText(mContext.getString( + R.string.download_status_installed, installedVersion)); + txtStatus.setTextColor(ThemeUtil.getThemeColor(mContext, + R.attr.download_status_installed)); txtStatus.setVisibility(View.VISIBLE); } else { txtStatus.setVisibility(View.GONE); @@ -321,8 +360,8 @@ public void bindView(View view, Context context, Cursor cursor) { String creationDate = mDateFormatter.format(new Date(created)); String updateDate = mDateFormatter.format(new Date(updated)); - ((TextView) view.findViewById(R.id.timestamps)).setText( - getString(R.string.download_timestamps, creationDate, updateDate)); + ((TextView) view.findViewById(R.id.timestamps)).setText(getString( + R.string.download_timestamps, creationDate, updateDate)); } } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/DownloadReceiver.java b/app/src/main/java/de/robv/android/xposed/installer/DownloadReceiver.java index 12e51e2d6..ac2fbef88 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/DownloadReceiver.java +++ b/app/src/main/java/de/robv/android/xposed/installer/DownloadReceiver.java @@ -4,6 +4,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; + import de.robv.android.xposed.installer.util.DownloadsUtil; public class DownloadReceiver extends BroadcastReceiver { @@ -11,7 +12,8 @@ public class DownloadReceiver extends BroadcastReceiver { public void onReceive(final Context context, final Intent intent) { String action = intent.getAction(); if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { - long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); + long downloadId = intent + .getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); DownloadsUtil.triggerDownloadFinishedCallback(context, downloadId); } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/InstallerFragment.java b/app/src/main/java/de/robv/android/xposed/installer/InstallerFragment.java index 54847fd85..4a0a9587e 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/InstallerFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/InstallerFragment.java @@ -1,21 +1,13 @@ package de.robv.android.xposed.installer; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - import android.app.Activity; import android.app.AlertDialog; -import android.support.v4.app.Fragment; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Looper; +import android.support.v4.app.Fragment; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -23,6 +15,15 @@ import android.widget.Button; import android.widget.CheckBox; import android.widget.TextView; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + import de.robv.android.xposed.installer.util.AssetUtil; import de.robv.android.xposed.installer.util.NavUtil; import de.robv.android.xposed.installer.util.NotificationUtil; @@ -30,23 +31,42 @@ import de.robv.android.xposed.installer.util.ThemeUtil; public class InstallerFragment extends Fragment { - private String APP_PROCESS_NAME = null; - private final String BINARIES_FOLDER = AssetUtil.getBinariesFolder(); private static final String JAR_PATH = "/system/framework/XposedBridge.jar"; private static final String JAR_PATH_NEWVERSION = JAR_PATH + ".newversion"; + private static final String PREF_LAST_SEEN_BINARY = "last_seen_binary"; + private static final int INSTALL_MODE_NORMAL = 0; + private static final int INSTALL_MODE_RECOVERY_AUTO = 1; + private static final int INSTALL_MODE_RECOVERY_MANUAL = 2; + private final String BINARIES_FOLDER = AssetUtil.getBinariesFolder(); private final LinkedList mCompatibilityErrors = new LinkedList(); + private String APP_PROCESS_NAME = null; private RootUtil mRootUtil = new RootUtil(); private boolean mHadSegmentationFault = false; - - private static final String PREF_LAST_SEEN_BINARY = "last_seen_binary"; - private ProgressDialog dlgProgress; private TextView txtInstallError, txtKnownIssue; - private Button btnInstallMode, btnInstall, btnUninstall, btnSoftReboot, btnReboot; + private Button btnInstallMode, btnInstall, btnUninstall, btnSoftReboot, + btnReboot; - private static final int INSTALL_MODE_NORMAL = 0; - private static final int INSTALL_MODE_RECOVERY_AUTO = 1; - private static final int INSTALL_MODE_RECOVERY_MANUAL = 2; + private static int extractIntPart(String str) { + int result = 0, length = str.length(); + for (int offset = 0; offset < length; offset++) { + char c = str.charAt(offset); + if ('0' <= c && c <= '9') + result = result * 10 + (c - '0'); + else + break; + } + return result; + } + + private static boolean checkClassExists(String className) { + try { + Class.forName(className); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } @Override public void onActivityCreated(Bundle savedInstanceState) { @@ -63,7 +83,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, View v = inflater.inflate(R.layout.tab_installer, container, false); btnInstallMode = (Button) v.findViewById(R.id.framework_install_mode); - txtInstallError = (TextView) v.findViewById(R.id.framework_install_errors); + txtInstallError = (TextView) v + .findViewById(R.id.framework_install_errors); txtKnownIssue = (TextView) v.findViewById(R.id.framework_known_issue); btnInstall = (Button) v.findViewById(R.id.btnInstall); @@ -74,105 +95,101 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, btnInstallMode.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent intent = new Intent(getActivity(), XposedBaseActivity.class); + Intent intent = new Intent(getActivity(), + XposedBaseActivity.class); startActivity(intent); } }); // FIXME /* - boolean isCompatible = false; - if (BINARIES_FOLDER == null) { - // incompatible processor architecture - } else if (Build.VERSION.SDK_INT == 15) { - APP_PROCESS_NAME = BINARIES_FOLDER + "app_process_xposed_sdk15"; - isCompatible = checkCompatibility(); - - } else if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 19) { - APP_PROCESS_NAME = BINARIES_FOLDER + "app_process_xposed_sdk16"; - isCompatible = checkCompatibility(); - - } else if (Build.VERSION.SDK_INT > 19) { - APP_PROCESS_NAME = BINARIES_FOLDER + "app_process_xposed_sdk16"; - isCompatible = checkCompatibility(); - if (isCompatible) { - txtInstallError.setText(String.format(getString(R.string.not_tested_but_compatible), Build.VERSION.SDK_INT)); - txtInstallError.setVisibility(View.VISIBLE); - } - } - */ + * boolean isCompatible = false; if (BINARIES_FOLDER == null) { // + * incompatible processor architecture } else if (Build.VERSION.SDK_INT + * == 15) { APP_PROCESS_NAME = BINARIES_FOLDER + + * "app_process_xposed_sdk15"; isCompatible = checkCompatibility(); + * + * } else if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= + * 19) { APP_PROCESS_NAME = BINARIES_FOLDER + + * "app_process_xposed_sdk16"; isCompatible = checkCompatibility(); + * + * } else if (Build.VERSION.SDK_INT > 19) { APP_PROCESS_NAME = + * BINARIES_FOLDER + "app_process_xposed_sdk16"; isCompatible = + * checkCompatibility(); if (isCompatible) { + * txtInstallError.setText(String.format(getString(R.string. + * not_tested_but_compatible), Build.VERSION.SDK_INT)); + * txtInstallError.setVisibility(View.VISIBLE); } } + */ // FIXME /* - if (isCompatible) { - btnInstall.setOnClickListener(new AsyncClickListener(btnInstall.getText()) { - @Override - public void onAsyncClick(View v) { - final boolean success = install(); - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - refreshVersions(); - if (success) - ModuleUtil.getInstance().updateModulesList(false); - - // Start tracking the last seen version, irrespective of the installation method and the outcome. - // 0 or a stale version might be registered, if a recovery installation was requested - // It will get up to date when the last seen version is updated on a later panel startup - XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, appProcessInstalledVersion).commit(); - // Dismiss any warning already being displayed - getView().findViewById(R.id.install_reverted_warning).setVisibility(View.GONE); - } - }); - } - }); - } else { - String errorText = String.format(getString(R.string.phone_not_compatible), Build.VERSION.SDK_INT, Build.CPU_ABI); - if (!mCompatibilityErrors.isEmpty()) - errorText += "\n\n" + TextUtils.join("\n", mCompatibilityErrors); - txtInstallError.setText(errorText); - txtInstallError.setVisibility(View.VISIBLE); - btnInstall.setEnabled(false); - } - - btnUninstall.setOnClickListener(new AsyncClickListener(btnUninstall.getText()) { - @Override - public void onAsyncClick(View v) { - uninstall(); - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - refreshVersions(); - - // Update tracking of the last seen version - if (appProcessInstalledVersion == 0) { - // Uninstall completed, check if an Xposed binary doesn't reappear - XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, -1).commit(); - } else { - // Xposed binary still in place. - // Stop tracking last seen version, as uninstall might complete later or not - XposedApp.getPreferences().edit().remove(PREF_LAST_SEEN_BINARY).commit(); - } - // Dismiss any warning already being displayed - getView().findViewById(R.id.install_reverted_warning).setVisibility(View.GONE); - } - }); - } - }); - */ + * if (isCompatible) { btnInstall.setOnClickListener(new + * AsyncClickListener(btnInstall.getText()) { + * + * @Override public void onAsyncClick(View v) { final boolean success = + * install(); getActivity().runOnUiThread(new Runnable() { + * + * @Override public void run() { refreshVersions(); if (success) + * ModuleUtil.getInstance().updateModulesList(false); + * + * // Start tracking the last seen version, irrespective of the + * installation method and the outcome. // 0 or a stale version might be + * registered, if a recovery installation was requested // It will get + * up to date when the last seen version is updated on a later panel + * startup + * XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, + * appProcessInstalledVersion).commit(); // Dismiss any warning already + * being displayed + * getView().findViewById(R.id.install_reverted_warning).setVisibility( + * View.GONE); } }); } }); } else { String errorText = + * String.format(getString(R.string.phone_not_compatible), + * Build.VERSION.SDK_INT, Build.CPU_ABI); if + * (!mCompatibilityErrors.isEmpty()) errorText += "\n\n" + + * TextUtils.join("\n", mCompatibilityErrors); + * txtInstallError.setText(errorText); + * txtInstallError.setVisibility(View.VISIBLE); + * btnInstall.setEnabled(false); } + * + * btnUninstall.setOnClickListener(new + * AsyncClickListener(btnUninstall.getText()) { + * + * @Override public void onAsyncClick(View v) { uninstall(); + * getActivity().runOnUiThread(new Runnable() { + * + * @Override public void run() { refreshVersions(); + * + * // Update tracking of the last seen version if + * (appProcessInstalledVersion == 0) { // Uninstall completed, check if + * an Xposed binary doesn't reappear + * XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, + * -1).commit(); } else { // Xposed binary still in place. // Stop + * tracking last seen version, as uninstall might complete later or not + * XposedApp.getPreferences().edit().remove(PREF_LAST_SEEN_BINARY). + * commit(); } // Dismiss any warning already being displayed + * getView().findViewById(R.id.install_reverted_warning).setVisibility( + * View.GONE); } }); } }); + */ - String installedXposedVersion = XposedApp.getXposedProp().get("version"); + String installedXposedVersion = XposedApp.getXposedProp() + .get("version"); if (installedXposedVersion == null) { txtInstallError.setText(R.string.installation_lollipop); - txtInstallError.setTextColor(getResources().getColor(R.color.warning)); + txtInstallError + .setTextColor(getResources().getColor(R.color.warning)); } else { - int installedXposedVersionInt = extractIntPart(installedXposedVersion); - if (installedXposedVersionInt == XposedApp.getActiveXposedVersion()) { - txtInstallError.setText(getString(R.string.installed_lollipop, installedXposedVersion)); - txtInstallError.setTextColor(getResources().getColor(R.color.darker_green)); + int installedXposedVersionInt = extractIntPart( + installedXposedVersion); + if (installedXposedVersionInt == XposedApp + .getActiveXposedVersion()) { + txtInstallError.setText(getString(R.string.installed_lollipop, + installedXposedVersion)); + txtInstallError.setTextColor( + getResources().getColor(R.color.darker_green)); } else { - txtInstallError.setText(getString(R.string.installed_lollipop_inactive, installedXposedVersion)); - txtInstallError.setTextColor(getResources().getColor(R.color.warning)); + txtInstallError + .setText(getString(R.string.installed_lollipop_inactive, + installedXposedVersion)); + txtInstallError + .setTextColor(getResources().getColor(R.color.warning)); } } txtInstallError.setVisibility(View.VISIBLE); @@ -184,9 +201,11 @@ public void run() { btnReboot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - areYouSure(R.string.reboot, new AsyncDialogClickListener(btnReboot.getText()) { + areYouSure(R.string.reboot, + new AsyncDialogClickListener(btnReboot.getText()) { @Override - public void onAsyncClick(DialogInterface dialog, int which) { + public void onAsyncClick(DialogInterface dialog, + int which) { reboot(null); } }); @@ -196,88 +215,87 @@ public void onAsyncClick(DialogInterface dialog, int which) { btnSoftReboot.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - areYouSure(R.string.soft_reboot, new AsyncDialogClickListener(btnSoftReboot.getText()) { + areYouSure(R.string.soft_reboot, + new AsyncDialogClickListener(btnSoftReboot.getText()) { @Override - public void onAsyncClick(DialogInterface dialog, int which) { + public void onAsyncClick(DialogInterface dialog, + int which) { softReboot(); } }); } }); - if (!XposedApp.getPreferences().getBoolean("hide_install_warning", false)) { - final View dontShowAgainView = inflater.inflate(R.layout.dialog_install_warning, null); + if (!XposedApp.getPreferences().getBoolean("hide_install_warning", + false)) { + final View dontShowAgainView = inflater + .inflate(R.layout.dialog_install_warning, null); new AlertDialog.Builder(getActivity()) - .setTitle(R.string.install_warning_title) - .setView(dontShowAgainView) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - CheckBox checkBox = (CheckBox) dontShowAgainView.findViewById(android.R.id.checkbox); - if (checkBox.isChecked()) - XposedApp.getPreferences().edit().putBoolean("hide_install_warning", true).commit(); - } - }) - .setCancelable(false) - .show(); + .setTitle(R.string.install_warning_title) + .setView(dontShowAgainView) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, + int which) { + CheckBox checkBox = (CheckBox) dontShowAgainView + .findViewById( + android.R.id.checkbox); + if (checkBox.isChecked()) + XposedApp.getPreferences().edit() + .putBoolean( + "hide_install_warning", + true) + .commit(); + } + }) + .setCancelable(false).show(); } - /* Detection of reverts to /system/bin/app_process. - * LastSeenBinary can be: - * missing - do nothing - * -1 - Uninstall was performed, check if an Xposed binary didn't reappear - * >= 0 - Make sure a downgrade or non-xposed binary doesn't occur - * Also auto-update the value to the latest version found + /* + * Detection of reverts to /system/bin/app_process. LastSeenBinary can + * be: missing - do nothing -1 - Uninstall was performed, check if an + * Xposed binary didn't reappear >= 0 - Make sure a downgrade or + * non-xposed binary doesn't occur Also auto-update the value to the + * latest version found */ /* - int lastSeenBinary = XposedApp.getPreferences().getInt(PREF_LAST_SEEN_BINARY, Integer.MIN_VALUE); - if (lastSeenBinary != Integer.MIN_VALUE) { - final View vInstallRevertedWarning = v.findViewById(R.id.install_reverted_warning); - final TextView txtInstallRevertedWarning = (TextView) v.findViewById(R.id.install_reverted_warning_text); - vInstallRevertedWarning.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // Stop tracking and dismiss the info panel - XposedApp.getPreferences().edit().remove(PREF_LAST_SEEN_BINARY).commit(); - vInstallRevertedWarning.setVisibility(View.GONE); - } - }); - - if (lastSeenBinary < 0 && appProcessInstalledVersion > 0) { - // Uninstall was previously completed but an Xposed binary has reappeared - txtInstallRevertedWarning.setText(getString(R.string.uninstall_reverted, - versionToText(appProcessInstalledVersion))); - vInstallRevertedWarning.setVisibility(View.VISIBLE); - } else if (appProcessInstalledVersion < lastSeenBinary) { - // Previously installed binary was either restored to stock or downgraded, probably - // following a reboot on a locked system - txtInstallRevertedWarning.setText(getString(R.string.install_reverted, - versionToText(lastSeenBinary), versionToText(appProcessInstalledVersion))); - vInstallRevertedWarning.setVisibility(View.VISIBLE); - } else if (appProcessInstalledVersion > lastSeenBinary) { - // Current binary is newer, register it and keep monitoring for future downgrades - XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, appProcessInstalledVersion).commit(); - } else { - // All is ok - } - } - */ + * int lastSeenBinary = + * XposedApp.getPreferences().getInt(PREF_LAST_SEEN_BINARY, + * Integer.MIN_VALUE); if (lastSeenBinary != Integer.MIN_VALUE) { final + * View vInstallRevertedWarning = + * v.findViewById(R.id.install_reverted_warning); final TextView + * txtInstallRevertedWarning = (TextView) + * v.findViewById(R.id.install_reverted_warning_text); + * vInstallRevertedWarning.setOnClickListener(new View.OnClickListener() + * { + * + * @Override public void onClick(View v) { // Stop tracking and dismiss + * the info panel + * XposedApp.getPreferences().edit().remove(PREF_LAST_SEEN_BINARY). + * commit(); vInstallRevertedWarning.setVisibility(View.GONE); } }); + * + * if (lastSeenBinary < 0 && appProcessInstalledVersion > 0) { // + * Uninstall was previously completed but an Xposed binary has + * reappeared txtInstallRevertedWarning.setText(getString(R.string. + * uninstall_reverted, versionToText(appProcessInstalledVersion))); + * vInstallRevertedWarning.setVisibility(View.VISIBLE); } else if + * (appProcessInstalledVersion < lastSeenBinary) { // Previously + * installed binary was either restored to stock or downgraded, probably + * // following a reboot on a locked system + * txtInstallRevertedWarning.setText(getString(R.string. + * install_reverted, versionToText(lastSeenBinary), + * versionToText(appProcessInstalledVersion))); + * vInstallRevertedWarning.setVisibility(View.VISIBLE); } else if + * (appProcessInstalledVersion > lastSeenBinary) { // Current binary is + * newer, register it and keep monitoring for future downgrades + * XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, + * appProcessInstalledVersion).commit(); } else { // All is ok } } + */ return v; } - private static int extractIntPart(String str) { - int result = 0, length = str.length(); - for (int offset = 0; offset < length; offset++) { - char c = str.charAt(offset); - if ('0' <= c && c <= '9') - result = result * 10 + (c - '0'); - else - break; - } - return result; - } - @Override public void onResume() { super.onResume(); @@ -293,56 +311,9 @@ public void onDestroy() { mRootUtil.dispose(); } - private abstract class AsyncClickListener implements View.OnClickListener { - private final CharSequence mProgressDlgText; - - public AsyncClickListener(CharSequence progressDlgText) { - mProgressDlgText = progressDlgText; - } - - @Override - public final void onClick(final View v) { - if (mProgressDlgText != null) { - dlgProgress.setMessage(mProgressDlgText); - dlgProgress.show(); - } - new Thread() { - public void run() { - onAsyncClick(v); - dlgProgress.dismiss(); - } - }.start(); - } - - protected abstract void onAsyncClick(View v); - } - - private abstract class AsyncDialogClickListener implements DialogInterface.OnClickListener { - private final CharSequence mProgressDlgText; - - public AsyncDialogClickListener(CharSequence progressDlgText) { - mProgressDlgText = progressDlgText; - } - - @Override - public void onClick(final DialogInterface dialog, final int which) { - if (mProgressDlgText != null) { - dlgProgress.setMessage(mProgressDlgText); - dlgProgress.show(); - } - new Thread() { - public void run() { - onAsyncClick(dialog, which); - dlgProgress.dismiss(); - } - }.start(); - } - - protected abstract void onAsyncClick(DialogInterface dialog, int which); - } - private String versionToText(int version) { - return (version == 0) ? getString(R.string.none) : Integer.toString(version); + return (version == 0) ? getString(R.string.none) + : Integer.toString(version); } private void refreshKnownIssue() { @@ -353,7 +324,8 @@ private void refreshKnownIssue() { issueName = "Aliyun OS"; issueLink = "http://forum.xda-developers.com/showpost.php?p=52289793&postcount=5"; - } else if (new File("/data/miui/DexspyInstaller.jar").exists() || checkClassExists("miui.dexspy.DexspyInstaller")) { + } else if (new File("/data/miui/DexspyInstaller.jar").exists() + || checkClassExists("miui.dexspy.DexspyInstaller")) { issueName = "MIUI/Dexspy"; issueLink = "http://forum.xda-developers.com/showpost.php?p=52291098&postcount=6"; @@ -361,15 +333,17 @@ private void refreshKnownIssue() { issueName = "Segmentation fault"; issueLink = "http://forum.xda-developers.com/showpost.php?p=52292102&postcount=7"; - } else if (checkClassExists("com.huawei.android.content.res.ResourcesEx") - || checkClassExists("android.content.res.NubiaResources")) { + } else + if (checkClassExists("com.huawei.android.content.res.ResourcesEx") + || checkClassExists("android.content.res.NubiaResources")) { issueName = "Resources subclass"; issueLink = "http://forum.xda-developers.com/showpost.php?p=52801382&postcount=8"; } if (issueName != null) { final String issueLinkFinal = issueLink; - txtKnownIssue.setText(getString(R.string.install_known_issue, issueName)); + txtKnownIssue.setText( + getString(R.string.install_known_issue, issueName)); txtKnownIssue.setVisibility(View.VISIBLE); txtKnownIssue.setOnClickListener(new View.OnClickListener() { @Override @@ -378,22 +352,16 @@ public void onClick(View v) { } }); if (btnInstall.isEnabled()) - btnInstall.setTextColor(getResources().getColor(R.color.warning)); - txtInstallError.setTextColor(ThemeUtil.getThemeColor(getActivity(), android.R.attr.textColorTertiary)); + btnInstall + .setTextColor(getResources().getColor(R.color.warning)); + txtInstallError.setTextColor(ThemeUtil.getThemeColor(getActivity(), + android.R.attr.textColorTertiary)); } else { txtKnownIssue.setVisibility(View.GONE); // FIXME - //btnInstall.setTextColor(ThemeUtil.getThemeColor(getActivity(), android.R.attr.textColorPrimary)); - //txtInstallError.setTextColor(getResources().getColor(R.color.warning)); - } - } - - private static boolean checkClassExists(String className) { - try { - Class.forName(className); - return true; - } catch (ClassNotFoundException e) { - return false; + // btnInstall.setTextColor(ThemeUtil.getThemeColor(getActivity(), + // android.R.attr.textColorPrimary)); + // txtInstallError.setTextColor(getResources().getColor(R.color.warning)); } } @@ -409,29 +377,29 @@ public void run() { } AlertDialog dialog = new AlertDialog.Builder(getActivity()) - .setMessage(result) - .setPositiveButton(android.R.string.ok, null) - .create(); + .setMessage(result).setPositiveButton(android.R.string.ok, null) + .create(); dialog.show(); - TextView txtMessage = (TextView) dialog.findViewById(android.R.id.message); + TextView txtMessage = (TextView) dialog + .findViewById(android.R.id.message); txtMessage.setTextSize(14); - mHadSegmentationFault = result.toLowerCase(Locale.US).contains("segmentation fault"); + mHadSegmentationFault = result.toLowerCase(Locale.US) + .contains("segmentation fault"); refreshKnownIssue(); } - private void areYouSure(int messageTextId, DialogInterface.OnClickListener yesHandler) { - new AlertDialog.Builder(getActivity()) - .setTitle(messageTextId) - .setMessage(R.string.areyousure) - .setIconAttribute(android.R.attr.alertDialogIcon) - .setPositiveButton(android.R.string.yes, yesHandler) - .setNegativeButton(android.R.string.no, null) - .create() - .show(); + private void areYouSure(int messageTextId, + DialogInterface.OnClickListener yesHandler) { + new AlertDialog.Builder(getActivity()).setTitle(messageTextId) + .setMessage(R.string.areyousure) + .setIconAttribute(android.R.attr.alertDialogIcon) + .setPositiveButton(android.R.string.yes, yesHandler) + .setNegativeButton(android.R.string.no, null).create().show(); } - private void showConfirmDialog(final String message, final DialogInterface.OnClickListener yesHandler, + private void showConfirmDialog(final String message, + final DialogInterface.OnClickListener yesHandler, final DialogInterface.OnClickListener noHandler) { if (Looper.myLooper() != Looper.getMainLooper()) { getActivity().runOnUiThread(new Runnable() { @@ -444,15 +412,16 @@ public void run() { } AlertDialog dialog = new AlertDialog.Builder(getActivity()) - .setMessage(message) - .setPositiveButton(android.R.string.yes, yesHandler) - .setNegativeButton(android.R.string.no, noHandler) - .create(); + .setMessage(message) + .setPositiveButton(android.R.string.yes, yesHandler) + .setNegativeButton(android.R.string.no, noHandler).create(); dialog.show(); - TextView txtMessage = (TextView) dialog.findViewById(android.R.id.message); + TextView txtMessage = (TextView) dialog + .findViewById(android.R.id.message); txtMessage.setTextSize(14); - mHadSegmentationFault = message.toLowerCase(Locale.US).contains("segmentation fault"); + mHadSegmentationFault = message.toLowerCase(Locale.US) + .contains("segmentation fault"); refreshKnownIssue(); } @@ -466,19 +435,24 @@ private boolean checkAppProcessCompatibility() { if (APP_PROCESS_NAME == null) return false; - File testFile = AssetUtil.writeAssetToCacheFile(APP_PROCESS_NAME, "app_process", 00700); + File testFile = AssetUtil.writeAssetToCacheFile(APP_PROCESS_NAME, + "app_process", 00700); if (testFile == null) { - mCompatibilityErrors.add("could not write app_process to cache"); + mCompatibilityErrors + .add("could not write app_process to cache"); return false; } - Process p = Runtime.getRuntime().exec(new String[] { testFile.getAbsolutePath(), "--xposedversion" }); + Process p = Runtime.getRuntime().exec(new String[] { + testFile.getAbsolutePath(), "--xposedversion" }); - BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedReader stdout = new BufferedReader( + new InputStreamReader(p.getInputStream())); String result = stdout.readLine(); stdout.close(); - BufferedReader stderr = new BufferedReader(new InputStreamReader(p.getErrorStream())); + BufferedReader stderr = new BufferedReader( + new InputStreamReader(p.getErrorStream())); String errorLine; while ((errorLine = stderr.readLine()) != null) { mCompatibilityErrors.add(errorLine); @@ -504,7 +478,8 @@ private boolean startShell() { } private int getInstallMode() { - int mode = XposedApp.getPreferences().getInt("install_mode", INSTALL_MODE_NORMAL); + int mode = XposedApp.getPreferences().getInt("install_mode", + INSTALL_MODE_NORMAL); if (mode < INSTALL_MODE_NORMAL || mode > INSTALL_MODE_RECOVERY_MANUAL) mode = INSTALL_MODE_NORMAL; return mode; @@ -532,85 +507,116 @@ private boolean install() { List messages = new LinkedList(); boolean showAlert = true; try { - messages.add(getString(R.string.sdcard_location, XposedApp.getInstance().getExternalFilesDir(null))); + messages.add(getString(R.string.sdcard_location, + XposedApp.getInstance().getExternalFilesDir(null))); messages.add(""); - messages.add(getString(R.string.file_copying, "Xposed-Disabler-Recovery.zip")); - if (AssetUtil.writeAssetToSdcardFile("Xposed-Disabler-Recovery.zip", 00644) == null) { + messages.add(getString(R.string.file_copying, + "Xposed-Disabler-Recovery.zip")); + if (AssetUtil.writeAssetToSdcardFile("Xposed-Disabler-Recovery.zip", + 00644) == null) { messages.add(""); - messages.add(getString(R.string.file_extract_failed, "Xposed-Disabler-Recovery.zip")); + messages.add(getString(R.string.file_extract_failed, + "Xposed-Disabler-Recovery.zip")); return false; } - File appProcessFile = AssetUtil.writeAssetToFile(APP_PROCESS_NAME, new File(XposedApp.BASE_DIR + "bin/app_process"), 00700); + File appProcessFile = AssetUtil.writeAssetToFile(APP_PROCESS_NAME, + new File(XposedApp.BASE_DIR + "bin/app_process"), 00700); if (appProcessFile == null) { - showAlert(getString(R.string.file_extract_failed, "app_process")); + showAlert( + getString(R.string.file_extract_failed, "app_process")); return false; } if (installMode == INSTALL_MODE_NORMAL) { // Normal installation - messages.add(getString(R.string.file_mounting_writable, "/system")); - if (mRootUtil.executeWithBusybox("mount -o remount,rw /system", messages) != 0) { - messages.add(getString(R.string.file_mount_writable_failed, "/system")); + messages.add( + getString(R.string.file_mounting_writable, "/system")); + if (mRootUtil.executeWithBusybox("mount -o remount,rw /system", + messages) != 0) { + messages.add(getString(R.string.file_mount_writable_failed, + "/system")); messages.add(getString(R.string.file_trying_to_continue)); } if (new File("/system/bin/app_process.orig").exists()) { - messages.add(getString(R.string.file_backup_already_exists, "/system/bin/app_process.orig")); + messages.add(getString(R.string.file_backup_already_exists, + "/system/bin/app_process.orig")); } else { - if (mRootUtil.executeWithBusybox("cp -a /system/bin/app_process /system/bin/app_process.orig", messages) != 0) { + if (mRootUtil.executeWithBusybox( + "cp -a /system/bin/app_process /system/bin/app_process.orig", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_backup_failed, "/system/bin/app_process")); + messages.add(getString(R.string.file_backup_failed, + "/system/bin/app_process")); return false; } else { - messages.add(getString(R.string.file_backup_successful, "/system/bin/app_process.orig")); + messages.add(getString(R.string.file_backup_successful, + "/system/bin/app_process.orig")); } mRootUtil.executeWithBusybox("sync", messages); } messages.add(getString(R.string.file_copying, "app_process")); - if (mRootUtil.executeWithBusybox("cp -a " + appProcessFile.getAbsolutePath() + " /system/bin/app_process", messages) != 0) { + if (mRootUtil + .executeWithBusybox( + "cp -a " + appProcessFile.getAbsolutePath() + + " /system/bin/app_process", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_copy_failed, "app_process", "/system/bin")); + messages.add(getString(R.string.file_copy_failed, + "app_process", "/system/bin")); return false; } - if (mRootUtil.executeWithBusybox("chmod 755 /system/bin/app_process", messages) != 0) { + if (mRootUtil.executeWithBusybox( + "chmod 755 /system/bin/app_process", messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_set_perms_failed, "/system/bin/app_process")); + messages.add(getString(R.string.file_set_perms_failed, + "/system/bin/app_process")); return false; } - if (mRootUtil.executeWithBusybox("chown root:shell /system/bin/app_process", messages) != 0) { + if (mRootUtil.executeWithBusybox( + "chown root:shell /system/bin/app_process", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_set_owner_failed, "/system/bin/app_process")); + messages.add(getString(R.string.file_set_owner_failed, + "/system/bin/app_process")); return false; } } else if (installMode == INSTALL_MODE_RECOVERY_AUTO) { - if (!prepareAutoFlash(messages, "Xposed-Installer-Recovery.zip")) + if (!prepareAutoFlash(messages, + "Xposed-Installer-Recovery.zip")) return false; } else if (installMode == INSTALL_MODE_RECOVERY_MANUAL) { - if (!prepareManualFlash(messages, "Xposed-Installer-Recovery.zip")) + if (!prepareManualFlash(messages, + "Xposed-Installer-Recovery.zip")) return false; } File blocker = new File(XposedApp.BASE_DIR + "conf/disabled"); if (blocker.exists()) { - messages.add(getString(R.string.file_removing, blocker.getAbsolutePath())); - if (mRootUtil.executeWithBusybox("rm " + blocker.getAbsolutePath(), messages) != 0) { + messages.add(getString(R.string.file_removing, + blocker.getAbsolutePath())); + if (mRootUtil.executeWithBusybox( + "rm " + blocker.getAbsolutePath(), messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_remove_failed, blocker.getAbsolutePath())); + messages.add(getString(R.string.file_remove_failed, + blocker.getAbsolutePath())); return false; } } messages.add(getString(R.string.file_copying, "XposedBridge.jar")); - File jarFile = AssetUtil.writeAssetToFile("XposedBridge.jar", new File(JAR_PATH_NEWVERSION), 00644); + File jarFile = AssetUtil.writeAssetToFile("XposedBridge.jar", + new File(JAR_PATH_NEWVERSION), 00644); if (jarFile == null) { messages.add(""); - messages.add(getString(R.string.file_extract_failed, "XposedBridge.jar")); + messages.add(getString(R.string.file_extract_failed, + "XposedBridge.jar")); return false; } @@ -621,7 +627,8 @@ private boolean install() { if (installMode == INSTALL_MODE_NORMAL) offerReboot(messages); else - offerRebootToRecovery(messages, "Xposed-Installer-Recovery.zip", installMode); + offerRebootToRecovery(messages, "Xposed-Installer-Recovery.zip", + installMode); return true; @@ -646,47 +653,65 @@ private boolean uninstall() { List messages = new LinkedList(); boolean showAlert = true; try { - messages.add(getString(R.string.sdcard_location, XposedApp.getInstance().getExternalFilesDir(null))); + messages.add(getString(R.string.sdcard_location, + XposedApp.getInstance().getExternalFilesDir(null))); messages.add(""); if (installMode == INSTALL_MODE_NORMAL) { - messages.add(getString(R.string.file_mounting_writable, "/system")); - if (mRootUtil.executeWithBusybox("mount -o remount,rw /system", messages) != 0) { - messages.add(getString(R.string.file_mount_writable_failed, "/system")); + messages.add( + getString(R.string.file_mounting_writable, "/system")); + if (mRootUtil.executeWithBusybox("mount -o remount,rw /system", + messages) != 0) { + messages.add(getString(R.string.file_mount_writable_failed, + "/system")); messages.add(getString(R.string.file_trying_to_continue)); } - messages.add(getString(R.string.file_backup_restoring, "/system/bin/app_process.orig")); + messages.add(getString(R.string.file_backup_restoring, + "/system/bin/app_process.orig")); if (!new File("/system/bin/app_process.orig").exists()) { messages.add(""); - messages.add(getString(R.string.file_backup_not_found, "/system/bin/app_process.orig")); + messages.add(getString(R.string.file_backup_not_found, + "/system/bin/app_process.orig")); return false; } - if (mRootUtil.executeWithBusybox("mv /system/bin/app_process.orig /system/bin/app_process", messages) != 0) { + if (mRootUtil.executeWithBusybox( + "mv /system/bin/app_process.orig /system/bin/app_process", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_move_failed, "/system/bin/app_process.orig", "/system/bin/app_process")); + messages.add(getString(R.string.file_move_failed, + "/system/bin/app_process.orig", + "/system/bin/app_process")); return false; } - if (mRootUtil.executeWithBusybox("chmod 755 /system/bin/app_process", messages) != 0) { + if (mRootUtil.executeWithBusybox( + "chmod 755 /system/bin/app_process", messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_set_perms_failed, "/system/bin/app_process")); + messages.add(getString(R.string.file_set_perms_failed, + "/system/bin/app_process")); return false; } - if (mRootUtil.executeWithBusybox("chown root:shell /system/bin/app_process", messages) != 0) { + if (mRootUtil.executeWithBusybox( + "chown root:shell /system/bin/app_process", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_set_owner_failed, "/system/bin/app_process")); + messages.add(getString(R.string.file_set_owner_failed, + "/system/bin/app_process")); return false; } - // Might help on some SELinux-enforced ROMs, shouldn't hurt on others - mRootUtil.execute("/system/bin/restorecon /system/bin/app_process", null); + // Might help on some SELinux-enforced ROMs, shouldn't hurt on + // others + mRootUtil.execute( + "/system/bin/restorecon /system/bin/app_process", null); } else if (installMode == INSTALL_MODE_RECOVERY_AUTO) { if (!prepareAutoFlash(messages, "Xposed-Disabler-Recovery.zip")) return false; } else if (installMode == INSTALL_MODE_RECOVERY_MANUAL) { - if (!prepareManualFlash(messages, "Xposed-Disabler-Recovery.zip")) + if (!prepareManualFlash(messages, + "Xposed-Disabler-Recovery.zip")) return false; } @@ -695,7 +720,8 @@ private boolean uninstall() { if (installMode == INSTALL_MODE_NORMAL) offerReboot(messages); else - offerRebootToRecovery(messages, "Xposed-Disabler-Recovery.zip", installMode); + offerRebootToRecovery(messages, "Xposed-Disabler-Recovery.zip", + installMode); return true; @@ -709,10 +735,13 @@ private boolean uninstall() { private boolean prepareAutoFlash(List messages, String file) { if (mRootUtil.execute("ls /cache/recovery", null) != 0) { - messages.add(getString(R.string.file_creating_directory, "/cache/recovery")); - if (mRootUtil.executeWithBusybox("mkdir /cache/recovery", messages) != 0) { + messages.add(getString(R.string.file_creating_directory, + "/cache/recovery")); + if (mRootUtil.executeWithBusybox("mkdir /cache/recovery", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_create_directory_failed, "/cache/recovery")); + messages.add(getString(R.string.file_create_directory_failed, + "/cache/recovery")); return false; } } @@ -725,7 +754,8 @@ private boolean prepareAutoFlash(List messages, String file) { return false; } - if (mRootUtil.executeWithBusybox("cp -a " + tempFile.getAbsolutePath() + " /cache/recovery/" + file, messages) != 0) { + if (mRootUtil.executeWithBusybox("cp -a " + tempFile.getAbsolutePath() + + " /cache/recovery/" + file, messages) != 0) { messages.add(""); messages.add(getString(R.string.file_copy_failed, file, "/cache")); tempFile.delete(); @@ -735,9 +765,13 @@ private boolean prepareAutoFlash(List messages, String file) { tempFile.delete(); messages.add(getString(R.string.file_writing_recovery_command)); - if (mRootUtil.execute("echo \"--update_package=/cache/recovery/" + file + "\n--show_text\" > /cache/recovery/command", messages) != 0) { + if (mRootUtil.execute( + "echo \"--update_package=/cache/recovery/" + file + + "\n--show_text\" > /cache/recovery/command", + messages) != 0) { messages.add(""); - messages.add(getString(R.string.file_writing_recovery_command_failed)); + messages.add( + getString(R.string.file_writing_recovery_command_failed)); return false; } @@ -760,15 +794,17 @@ private void offerReboot(List messages) { messages.add(""); messages.add(getString(R.string.reboot_confirmation)); showConfirmDialog(TextUtils.join("\n", messages).trim(), - new AsyncDialogClickListener(getString(R.string.reboot)) { - @Override - protected void onAsyncClick(DialogInterface dialog, int which) { - reboot(null); - } - }, null); + new AsyncDialogClickListener(getString(R.string.reboot)) { + @Override + protected void onAsyncClick(DialogInterface dialog, + int which) { + reboot(null); + } + }, null); } - private void offerRebootToRecovery(List messages, final String file, final int installMode) { + private void offerRebootToRecovery(List messages, final String file, + final int installMode) { if (installMode == INSTALL_MODE_RECOVERY_AUTO) messages.add(getString(R.string.auto_flash_note, file)); else @@ -777,23 +813,26 @@ private void offerRebootToRecovery(List messages, final String file, fin messages.add(""); messages.add(getString(R.string.reboot_recovery_confirmation)); showConfirmDialog(TextUtils.join("\n", messages).trim(), - new AsyncDialogClickListener(getString(R.string.reboot)) { - @Override - protected void onAsyncClick(DialogInterface dialog, int which) { - reboot("recovery"); - } - }, - new AsyncDialogClickListener(null) { - @Override - protected void onAsyncClick(DialogInterface dialog, int which) { - if (installMode == INSTALL_MODE_RECOVERY_AUTO) { - // clean up to avoid unwanted flashing - mRootUtil.executeWithBusybox("rm /cache/recovery/command", null); - mRootUtil.executeWithBusybox("rm /cache/recovery/" + file, null); - AssetUtil.removeBusybox(); + new AsyncDialogClickListener(getString(R.string.reboot)) { + @Override + protected void onAsyncClick(DialogInterface dialog, + int which) { + reboot("recovery"); } - } - }); + }, new AsyncDialogClickListener(null) { + @Override + protected void onAsyncClick(DialogInterface dialog, + int which) { + if (installMode == INSTALL_MODE_RECOVERY_AUTO) { + // clean up to avoid unwanted flashing + mRootUtil.executeWithBusybox( + "rm /cache/recovery/command", null); + mRootUtil.executeWithBusybox( + "rm /cache/recovery/" + file, null); + AssetUtil.removeBusybox(); + } + } + }); } private void softReboot() { @@ -801,7 +840,9 @@ private void softReboot() { return; List messages = new LinkedList(); - if (mRootUtil.execute("setprop ctl.restart surfaceflinger; setprop ctl.restart zygote", messages) != 0) { + if (mRootUtil.execute( + "setprop ctl.restart surfaceflinger; setprop ctl.restart zygote", + messages) != 0) { messages.add(""); messages.add(getString(R.string.reboot_failed)); showAlert(TextUtils.join("\n", messages).trim()); @@ -819,7 +860,8 @@ private void reboot(String mode) { command += " " + mode; if (mode.equals("recovery")) // create a flag used by some kernels to boot into recovery - mRootUtil.executeWithBusybox("touch /cache/recovery/boot", messages); + mRootUtil.executeWithBusybox("touch /cache/recovery/boot", + messages); } if (mRootUtil.executeWithBusybox(command, messages) != 0) { @@ -829,4 +871,53 @@ private void reboot(String mode) { } AssetUtil.removeBusybox(); } + + private abstract class AsyncClickListener implements View.OnClickListener { + private final CharSequence mProgressDlgText; + + public AsyncClickListener(CharSequence progressDlgText) { + mProgressDlgText = progressDlgText; + } + + @Override + public final void onClick(final View v) { + if (mProgressDlgText != null) { + dlgProgress.setMessage(mProgressDlgText); + dlgProgress.show(); + } + new Thread() { + public void run() { + onAsyncClick(v); + dlgProgress.dismiss(); + } + }.start(); + } + + protected abstract void onAsyncClick(View v); + } + + private abstract class AsyncDialogClickListener + implements DialogInterface.OnClickListener { + private final CharSequence mProgressDlgText; + + public AsyncDialogClickListener(CharSequence progressDlgText) { + mProgressDlgText = progressDlgText; + } + + @Override + public void onClick(final DialogInterface dialog, final int which) { + if (mProgressDlgText != null) { + dlgProgress.setMessage(mProgressDlgText); + dlgProgress.show(); + } + new Thread() { + public void run() { + onAsyncClick(dialog, which); + dlgProgress.dismiss(); + } + }.start(); + } + + protected abstract void onAsyncClick(DialogInterface dialog, int which); + } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/LogsFragment.java b/app/src/main/java/de/robv/android/xposed/installer/LogsFragment.java index c4f6ec4c8..b252e5dbb 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/LogsFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/LogsFragment.java @@ -1,14 +1,5 @@ package de.robv.android.xposed.installer; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.Calendar; - import android.annotation.SuppressLint; import android.content.Intent; import android.net.Uri; @@ -26,10 +17,20 @@ import android.widget.TextView; import android.widget.Toast; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Calendar; + public class LogsFragment extends Fragment { + private static final int MAX_LOG_SIZE = 2 * 1024 * 1024; // 2 MB private File mFileErrorLog = new File(XposedApp.BASE_DIR + "log/error.log"); - private File mFileErrorLogOld = new File(XposedApp.BASE_DIR + "log/error.log.old"); - private static final int MAX_LOG_SIZE = 2*1024*1024; // 2 MB + private File mFileErrorLogOld = new File( + XposedApp.BASE_DIR + "log/error.log.old"); private TextView mTxtLog; private ScrollView mSVLog; private HorizontalScrollView mHSVLog; @@ -41,7 +42,8 @@ public void onActivityCreated(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { View v = inflater.inflate(R.layout.tab_logs, container, false); mTxtLog = (TextView) v.findViewById(R.id.txtLog); mSVLog = (ScrollView) v.findViewById(R.id.svLog); @@ -58,18 +60,18 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.menu_refresh: - reloadErrorLog(); - return true; - case R.id.menu_send: - send(); - return true; - case R.id.menu_save: - save(); - return true; - case R.id.menu_clear: - clear(); - return true; + case R.id.menu_refresh: + reloadErrorLog(); + return true; + case R.id.menu_send: + send(); + return true; + case R.id.menu_save: + save(); + return true; + case R.id.menu_clear: + clear(); + return true; } return super.onOptionsItemSelected(item); } @@ -81,7 +83,9 @@ private void reloadErrorLog() { long skipped = skipLargeFile(fis, mFileErrorLog.length()); if (skipped > 0) { logContent.append("-----------------\n"); - logContent.append(getResources().getString(R.string.log_too_large, MAX_LOG_SIZE / 1024, skipped / 1024)); + logContent + .append(getResources().getString(R.string.log_too_large, + MAX_LOG_SIZE / 1024, skipped / 1024)); logContent.append("\n-----------------\n\n"); } Reader reader = new InputStreamReader(fis); @@ -92,7 +96,8 @@ private void reloadErrorLog() { } reader.close(); } catch (IOException e) { - logContent.append(getResources().getString(R.string.logs_load_failed)); + logContent.append( + getResources().getString(R.string.logs_load_failed)); logContent.append('\n'); logContent.append(e.getMessage()); } @@ -118,13 +123,15 @@ public void run() { private void clear() { try { - new FileOutputStream(mFileErrorLog).close();; + new FileOutputStream(mFileErrorLog).close(); mFileErrorLogOld.delete(); - Toast.makeText(getActivity(), R.string.logs_cleared, Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), R.string.logs_cleared, + Toast.LENGTH_SHORT).show(); reloadErrorLog(); } catch (IOException e) { Toast.makeText(getActivity(), - getResources().getString(R.string.logs_clear_failed) + "\n" + e.getMessage(), + getResources().getString(R.string.logs_clear_failed) + "\n" + + e.getMessage(), Toast.LENGTH_LONG).show(); return; } @@ -134,22 +141,29 @@ private void send() { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(mFileErrorLog)); - sendIntent.setType("application/text"); // text/plain is handled wrongly by too many apps - startActivity(Intent.createChooser(sendIntent, getResources().getString(R.string.menuSend))); + sendIntent.setType("application/text"); // text/plain is handled wrongly + // by too many apps + startActivity(Intent.createChooser(sendIntent, + getResources().getString(R.string.menuSend))); } @SuppressLint("DefaultLocale") private void save() { - if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - Toast.makeText(getActivity(), R.string.sdcard_not_writable, Toast.LENGTH_LONG).show(); + if (!Environment.getExternalStorageState() + .equals(Environment.MEDIA_MOUNTED)) { + Toast.makeText(getActivity(), R.string.sdcard_not_writable, + Toast.LENGTH_LONG).show(); return; } Calendar now = Calendar.getInstance(); - String filename = String.format("xposed_%s_%04d%02d%02d_%02d%02d%02d.log", "error", - now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, now.get(Calendar.DAY_OF_MONTH), - now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND)); - File targetFile = new File(getActivity().getExternalFilesDir(null), filename); + String filename = String.format( + "xposed_%s_%04d%02d%02d_%02d%02d%02d.log", "error", + now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, + now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY), + now.get(Calendar.MINUTE), now.get(Calendar.SECOND)); + File targetFile = new File(getActivity().getExternalFilesDir(null), + filename); try { FileInputStream in = new FileInputStream(mFileErrorLog); @@ -159,26 +173,30 @@ private void save() { if (skipped > 0) { StringBuilder logContent = new StringBuilder(512); logContent.append("-----------------\n"); - logContent.append(getResources().getString(R.string.log_too_large, MAX_LOG_SIZE / 1024, skipped / 1024)); + logContent + .append(getResources().getString(R.string.log_too_large, + MAX_LOG_SIZE / 1024, skipped / 1024)); logContent.append("\n-----------------\n\n"); out.write(logContent.toString().getBytes()); } byte[] buffer = new byte[1024]; int len; - while ((len = in.read(buffer)) > 0){ + while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); } catch (IOException e) { Toast.makeText(getActivity(), - getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), + getResources().getString(R.string.logs_save_failed) + "\n" + + e.getMessage(), Toast.LENGTH_LONG).show(); return; } - Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity(), targetFile.toString(), Toast.LENGTH_LONG) + .show(); } private long skipLargeFile(InputStream is, long length) throws IOException { diff --git a/app/src/main/java/de/robv/android/xposed/installer/ModulesFragment.java b/app/src/main/java/de/robv/android/xposed/installer/ModulesFragment.java index eac1fa3f1..8cb914c5c 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/ModulesFragment.java +++ b/app/src/main/java/de/robv/android/xposed/installer/ModulesFragment.java @@ -1,10 +1,5 @@ package de.robv.android.xposed.installer; -import java.text.Collator; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; - import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -32,6 +27,12 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; + +import java.text.Collator; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + import de.robv.android.xposed.installer.repo.RepoDb; import de.robv.android.xposed.installer.repo.RepoDb.RowNotFoundException; import de.robv.android.xposed.installer.util.ModuleUtil; @@ -51,6 +52,21 @@ public class ModulesFragment extends ListFragment implements ModuleListener { private ModuleUtil mModuleUtil; private ModuleAdapter mAdapter = null; private PackageManager mPm = null; + private Runnable reloadModules = new Runnable() { + public void run() { + mAdapter.setNotifyOnChange(false); + mAdapter.clear(); + mAdapter.addAll(mModuleUtil.getModules().values()); + final Collator col = Collator.getInstance(Locale.getDefault()); + mAdapter.sort(new Comparator() { + @Override + public int compare(InstalledModule lhs, InstalledModule rhs) { + return col.compare(lhs.getAppName(), rhs.getAppName()); + } + }); + mAdapter.notifyDataSetChanged(); + } + }; @Override public void onCreate(Bundle savedInstanceState) { @@ -59,9 +75,11 @@ public void onCreate(Bundle savedInstanceState) { mPm = getActivity().getPackageManager(); if (PLAY_STORE_LABEL == null) { try { - ApplicationInfo ai = mPm.getApplicationInfo(PLAY_STORE_PACKAGE, 0); + ApplicationInfo ai = mPm.getApplicationInfo(PLAY_STORE_PACKAGE, + 0); PLAY_STORE_LABEL = mPm.getApplicationLabel(ai).toString(); - } catch (NameNotFoundException ignored) {} + } catch (NameNotFoundException ignored) { + } } } @@ -83,16 +101,21 @@ public void onActivityCreated(Bundle savedInstanceState) { registerForContextMenu(getListView()); mModuleUtil.addListener(this); - ActionBar actionBar = ((WelcomeActivity) getActivity()).getSupportActionBar(); + ActionBar actionBar = ((WelcomeActivity) getActivity()) + .getSupportActionBar(); DisplayMetrics metrics = getResources().getDisplayMetrics(); - int sixDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, metrics); - int eightDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); - int toolBarDp = actionBar.getHeight() == 0 ? 196 : actionBar.getHeight(); + int sixDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + 6, metrics); + int eightDp = (int) TypedValue + .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); + int toolBarDp = actionBar.getHeight() == 0 ? 196 + : actionBar.getHeight(); getListView().setDivider(null); getListView().setDividerHeight(sixDp); - getListView().setPadding(eightDp, toolBarDp + eightDp, eightDp, eightDp); + getListView().setPadding(eightDp, toolBarDp + eightDp, eightDp, + eightDp); getListView().setClipToPadding(false); } @@ -110,24 +133,9 @@ public void onDestroyView() { mAdapter = null; } - private Runnable reloadModules = new Runnable() { - public void run() { - mAdapter.setNotifyOnChange(false); - mAdapter.clear(); - mAdapter.addAll(mModuleUtil.getModules().values()); - final Collator col = Collator.getInstance(Locale.getDefault()); - mAdapter.sort(new Comparator() { - @Override - public int compare(InstalledModule lhs, InstalledModule rhs) { - return col.compare(lhs.getAppName(), rhs.getAppName()); - } - }); - mAdapter.notifyDataSetChanged(); - } - }; - @Override - public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, InstalledModule module) { + public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, + String packageName, InstalledModule module) { getActivity().runOnUiThread(reloadModules); } @@ -151,23 +159,28 @@ public void onListItemClick(ListView l, View v, int position, long id) { if (launchIntent != null) startActivity(launchIntent); else - Toast.makeText(getActivity(), getActivity().getString(R.string.module_no_ui), Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity(), + getActivity().getString(R.string.module_no_ui), + Toast.LENGTH_LONG).show(); } @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { InstalledModule installedModule = getItemFromContextMenuInfo(menuInfo); if (installedModule == null) return; menu.setHeaderTitle(installedModule.getAppName()); - getActivity().getMenuInflater().inflate(R.menu.context_menu_modules, menu); + getActivity().getMenuInflater().inflate(R.menu.context_menu_modules, + menu); if (getSettingsIntent(installedModule.packageName) == null) menu.removeItem(R.id.menu_launch); try { - String support = RepoDb.getModuleSupport(installedModule.packageName); + String support = RepoDb + .getModuleSupport(installedModule.packageName); if (NavUtil.parseURL(support) == null) menu.removeItem(R.id.menu_support); } catch (RowNotFoundException e) { @@ -175,7 +188,8 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn menu.removeItem(R.id.menu_support); } - String installer = mPm.getInstallerPackageName(installedModule.packageName); + String installer = mPm + .getInstallerPackageName(installedModule.packageName); if (PLAY_STORE_LABEL != null && PLAY_STORE_PACKAGE.equals(installer)) menu.findItem(R.id.menu_play_store).setTitle(PLAY_STORE_LABEL); else @@ -194,18 +208,22 @@ public boolean onContextItemSelected(MenuItem item) { return true; case R.id.menu_download_updates: - Intent detailsIntent = new Intent(getActivity(), DownloadDetailsActivity.class); - detailsIntent.setData(Uri.fromParts("package", module.packageName, null)); + Intent detailsIntent = new Intent(getActivity(), + DownloadDetailsActivity.class); + detailsIntent.setData( + Uri.fromParts("package", module.packageName, null)); startActivity(detailsIntent); return true; case R.id.menu_support: - NavUtil.startURL(getActivity(), RepoDb.getModuleSupport(module.packageName)); + NavUtil.startURL(getActivity(), + RepoDb.getModuleSupport(module.packageName)); return true; case R.id.menu_play_store: Intent i = new Intent(android.content.Intent.ACTION_VIEW); - i.setData(Uri.parse(String.format(PLAY_STORE_LINK, module.packageName))); + i.setData(Uri.parse( + String.format(PLAY_STORE_LINK, module.packageName))); i.setPackage(PLAY_STORE_PACKAGE); try { startActivity(i); @@ -216,28 +234,33 @@ public boolean onContextItemSelected(MenuItem item) { return true; case R.id.menu_app_info: - startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.fromParts("package", module.packageName, null))); + startActivity(new Intent( + android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", module.packageName, null))); return true; case R.id.menu_uninstall: startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, - Uri.fromParts("package", module.packageName, null))); + Uri.fromParts("package", module.packageName, null))); return true; } return false; } - private InstalledModule getItemFromContextMenuInfo(ContextMenuInfo menuInfo) { + private InstalledModule getItemFromContextMenuInfo( + ContextMenuInfo menuInfo) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; int position = info.position - getListView().getHeaderViewsCount(); - return (position >= 0) ? (InstalledModule) getListAdapter().getItem(position) : null; + return (position >= 0) + ? (InstalledModule) getListAdapter().getItem(position) : null; } private Intent getSettingsIntent(String packageName) { - // taken from ApplicationPackageManager.getLaunchIntentForPackage(String) - // first looks for an Xposed-specific category, falls back to getLaunchIntentForPackage + // taken from + // ApplicationPackageManager.getLaunchIntentForPackage(String) + // first looks for an Xposed-specific category, falls back to + // getLaunchIntentForPackage PackageManager pm = getActivity().getPackageManager(); Intent intentToResolve = new Intent(Intent.ACTION_MAIN); @@ -251,7 +274,8 @@ private Intent getSettingsIntent(String packageName) { Intent intent = new Intent(intentToResolve); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClassName(ris.get(0).activityInfo.packageName, ris.get(0).activityInfo.name); + intent.setClassName(ris.get(0).activityInfo.packageName, + ris.get(0).activityInfo.name); return intent; } @@ -265,18 +289,27 @@ public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); if (convertView == null) { - // The reusable view was created for the first time, set up the listener on the checkbox - ((CheckBox) view.findViewById(R.id.checkbox)).setOnCheckedChangeListener(new OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - String packageName = (String) buttonView.getTag(); - boolean changed = mModuleUtil.isModuleEnabled(packageName) ^ isChecked; - if (changed) { - mModuleUtil.setModuleEnabled(packageName, isChecked); - mModuleUtil.updateModulesList(true); - } - } - }); + // The reusable view was created for the first time, set up the + // listener on the checkbox + ((CheckBox) view.findViewById(R.id.checkbox)) + .setOnCheckedChangeListener( + new OnCheckedChangeListener() { + @Override + public void onCheckedChanged( + CompoundButton buttonView, + boolean isChecked) { + String packageName = (String) buttonView + .getTag(); + boolean changed = mModuleUtil + .isModuleEnabled(packageName) + ^ isChecked; + if (changed) { + mModuleUtil.setModuleEnabled( + packageName, isChecked); + mModuleUtil.updateModulesList(true); + } + } + }); } InstalledModule item = getItem(position); @@ -285,18 +318,23 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { version.setText(item.versionName); // Store the package name in some views' tag for later access - ((CheckBox) view.findViewById(R.id.checkbox)).setTag(item.packageName); + view.findViewById(R.id.checkbox).setTag(item.packageName); view.setTag(item.packageName); - ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(item.getIcon()); + ((ImageView) view.findViewById(R.id.icon)) + .setImageDrawable(item.getIcon()); - TextView descriptionText = (TextView) view.findViewById(R.id.description); + TextView descriptionText = (TextView) view + .findViewById(R.id.description); if (!item.getDescription().isEmpty()) { descriptionText.setText(item.getDescription()); - descriptionText.setTextColor(ThemeUtil.getThemeColor(getContext(), android.R.attr.textColorSecondary)); + descriptionText.setTextColor(ThemeUtil.getThemeColor( + getContext(), android.R.attr.textColorSecondary)); } else { - descriptionText.setText(getString(R.string.module_empty_description)); - descriptionText.setTextColor(getResources().getColor(R.color.warning)); + descriptionText + .setText(getString(R.string.module_empty_description)); + descriptionText + .setTextColor(getResources().getColor(R.color.warning)); } CheckBox checkbox = (CheckBox) view.findViewById(R.id.checkbox); @@ -305,16 +343,20 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (item.minVersion == 0) { checkbox.setEnabled(false); - warningText.setText(getString(R.string.no_min_version_specified)); + warningText + .setText(getString(R.string.no_min_version_specified)); warningText.setVisibility(View.VISIBLE); - } else if (installedXposedVersion != 0 && item.minVersion > installedXposedVersion) { + } else if (installedXposedVersion != 0 + && item.minVersion > installedXposedVersion) { checkbox.setEnabled(false); - warningText.setText(String.format(getString(R.string.warning_xposed_min_version), + warningText.setText(String.format( + getString(R.string.warning_xposed_min_version), item.minVersion)); warningText.setVisibility(View.VISIBLE); } else if (item.minVersion < ModuleUtil.MIN_MODULE_VERSION) { checkbox.setEnabled(false); - warningText.setText(String.format(getString(R.string.warning_min_version_too_low), + warningText.setText(String.format( + getString(R.string.warning_min_version_too_low), item.minVersion, ModuleUtil.MIN_MODULE_VERSION)); warningText.setVisibility(View.VISIBLE); } else { diff --git a/app/src/main/java/de/robv/android/xposed/installer/PackageChangeReceiver.java b/app/src/main/java/de/robv/android/xposed/installer/PackageChangeReceiver.java index 2e4d2e02f..1be4af7c6 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/PackageChangeReceiver.java +++ b/app/src/main/java/de/robv/android/xposed/installer/PackageChangeReceiver.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; + import de.robv.android.xposed.installer.util.AssetUtil; import de.robv.android.xposed.installer.util.ModuleUtil; import de.robv.android.xposed.installer.util.ModuleUtil.InstalledModule; @@ -12,6 +13,11 @@ public class PackageChangeReceiver extends BroadcastReceiver { private final static ModuleUtil mModuleUtil = ModuleUtil.getInstance(); + private static String getPackageName(Intent intent) { + Uri uri = intent.getData(); + return (uri != null) ? uri.getSchemeSpecificPart() : null; + } + @Override public void onReceive(final Context context, final Intent intent) { if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) @@ -24,8 +30,10 @@ public void onReceive(final Context context, final Intent intent) { return; if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) { - // make sure that the change is for the complete package, not only a component - String[] components = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); + // make sure that the change is for the complete package, not only a + // component + String[] components = intent.getStringArrayExtra( + Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); if (components != null) { boolean isForPackage = false; for (String component : components) { @@ -45,9 +53,12 @@ public void onReceive(final Context context, final Intent intent) { return; } - InstalledModule module = ModuleUtil.getInstance().reloadSingleModule(packageName); - if (module == null || intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { - // Package being removed, disable it if it was a previously active Xposed mod + InstalledModule module = ModuleUtil.getInstance() + .reloadSingleModule(packageName); + if (module == null + || intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { + // Package being removed, disable it if it was a previously active + // Xposed mod if (mModuleUtil.isModuleEnabled(packageName)) { mModuleUtil.setModuleEnabled(packageName, false); mModuleUtil.updateModulesList(false); @@ -59,12 +70,8 @@ public void onReceive(final Context context, final Intent intent) { mModuleUtil.updateModulesList(false); NotificationUtil.showModulesUpdatedNotification(); } else { - NotificationUtil.showNotActivatedNotification(packageName, module.getAppName()); + NotificationUtil.showNotActivatedNotification(packageName, + module.getAppName()); } } - - private static String getPackageName(Intent intent) { - Uri uri = intent.getData(); - return (uri != null) ? uri.getSchemeSpecificPart() : null; - } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/SettingsActivity.java b/app/src/main/java/de/robv/android/xposed/installer/SettingsActivity.java index 26661cd9e..748c384f0 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/SettingsActivity.java +++ b/app/src/main/java/de/robv/android/xposed/installer/SettingsActivity.java @@ -5,7 +5,6 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Toast; @@ -18,101 +17,117 @@ import de.robv.android.xposed.installer.util.UIUtil; public class SettingsActivity extends XposedBaseActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - ThemeUtil.setTheme(this); - setContentView(R.layout.activity_container); - - if (UIUtil.isLollipop()) { - this.getWindow().setStatusBarColor(this.getResources().getColor(R.color.colorPrimaryDark)); - } - - Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(mToolbar); - - mToolbar.setNavigationOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - finish(); - } - }); - - ActionBar ab = getSupportActionBar(); - if (ab != null) { - ab.setTitle(R.string.nav_item_settings); - ab.setDisplayHomeAsUpEnabled(true); - } - - if (savedInstanceState == null) { - getFragmentManager().beginTransaction() - .add(R.id.container, new SettingsFragment()) - .commit(); - } - } - - public static class SettingsFragment extends PreferenceFragment { - private static final File mDisableResourcesFlag = new File(XposedApp.BASE_DIR + "conf/disable_resources"); - - public SettingsFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.prefs); - - findPreference("enable_downloads").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - boolean enabled = (Boolean) newValue; - if (enabled) { - preference.getEditor().putBoolean("enable_downloads", enabled).apply(); - RepoLoader.getInstance().refreshRepositories(); - RepoLoader.getInstance().triggerReload(true); - } else { - RepoLoader.getInstance().clear(true); - } - return true; - } - }); - - findPreference("release_type_global").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - RepoLoader.getInstance().setReleaseTypeGlobal((String) newValue); - return true; - } - }); - - CheckBoxPreference prefDisableResources = (CheckBoxPreference) findPreference("disable_resources"); - prefDisableResources.setChecked(mDisableResourcesFlag.exists()); - prefDisableResources.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - boolean enabled = (Boolean) newValue; - if (enabled) { - try { - mDisableResourcesFlag.createNewFile(); - } catch (IOException e) { - Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show(); - } - } else { - mDisableResourcesFlag.delete(); - } - return (enabled == mDisableResourcesFlag.exists()); - } - }); - - Preference prefTheme = findPreference("theme"); - prefTheme.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - getActivity().recreate(); - getActivity().finish(); // prevents 2 instances of settings from opening - return true; - } - }); - } - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeUtil.setTheme(this); + setContentView(R.layout.activity_container); + + if (UIUtil.isLollipop()) { + this.getWindow().setStatusBarColor( + this.getResources().getColor(R.color.colorPrimaryDark)); + } + + Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(mToolbar); + + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + finish(); + } + }); + + ActionBar ab = getSupportActionBar(); + if (ab != null) { + ab.setTitle(R.string.nav_item_settings); + ab.setDisplayHomeAsUpEnabled(true); + } + + if (savedInstanceState == null) { + getFragmentManager().beginTransaction() + .add(R.id.container, new SettingsFragment()).commit(); + } + } + + public static class SettingsFragment extends PreferenceFragment { + private static final File mDisableResourcesFlag = new File( + XposedApp.BASE_DIR + "conf/disable_resources"); + + public SettingsFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.prefs); + + findPreference("enable_downloads").setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, + Object newValue) { + boolean enabled = (Boolean) newValue; + if (enabled) { + preference.getEditor() + .putBoolean("enable_downloads", enabled) + .apply(); + RepoLoader.getInstance().refreshRepositories(); + RepoLoader.getInstance().triggerReload(true); + } else { + RepoLoader.getInstance().clear(true); + } + return true; + } + }); + + findPreference("release_type_global").setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, + Object newValue) { + RepoLoader.getInstance() + .setReleaseTypeGlobal((String) newValue); + return true; + } + }); + + CheckBoxPreference prefDisableResources = (CheckBoxPreference) findPreference( + "disable_resources"); + prefDisableResources.setChecked(mDisableResourcesFlag.exists()); + prefDisableResources.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, + Object newValue) { + boolean enabled = (Boolean) newValue; + if (enabled) { + try { + mDisableResourcesFlag.createNewFile(); + } catch (IOException e) { + Toast.makeText(getActivity(), + e.getMessage(), Toast.LENGTH_SHORT) + .show(); + } + } else { + mDisableResourcesFlag.delete(); + } + return (enabled == mDisableResourcesFlag.exists()); + } + }); + + Preference prefTheme = findPreference("theme"); + prefTheme.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, + Object newValue) { + getActivity().recreate(); + getActivity().finish(); // prevents 2 instances of + // settings from opening + return true; + } + }); + } + } } \ No newline at end of file diff --git a/app/src/main/java/de/robv/android/xposed/installer/SupportActivity.java b/app/src/main/java/de/robv/android/xposed/installer/SupportActivity.java index f8eaba887..d0012f66e 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/SupportActivity.java +++ b/app/src/main/java/de/robv/android/xposed/installer/SupportActivity.java @@ -1,8 +1,8 @@ package de.robv.android.xposed.installer; -import android.support.v4.app.Fragment; import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; @@ -21,7 +21,8 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_container); if (UIUtil.isLollipop()) { - this.getWindow().setStatusBarColor(this.getResources().getColor(R.color.colorPrimaryDark)); + this.getWindow().setStatusBarColor( + this.getResources().getColor(R.color.colorPrimaryDark)); } Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); @@ -42,8 +43,7 @@ public void onClick(View view) { if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() - .add(R.id.container, new SupportFragment()) - .commit(); + .add(R.id.container, new SupportFragment()).commit(); } } @@ -54,15 +54,21 @@ public void onCreate(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - ViewGroup vg = (ViewGroup) inflater.inflate(R.layout.tab_support, container, false); + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + ViewGroup vg = (ViewGroup) inflater.inflate(R.layout.tab_support, + container, false); - TextView txtModuleSupport = ((TextView) vg.findViewById(R.id.tab_support_module_description)); - txtModuleSupport.setText(getString(R.string.support_modules_description, getString(R.string.module_support))); + TextView txtModuleSupport = ((TextView) vg + .findViewById(R.id.tab_support_module_description)); + txtModuleSupport + .setText(getString(R.string.support_modules_description, + getString(R.string.module_support))); txtModuleSupport.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent intent = new Intent(getActivity(), XposedBaseActivity.class); + Intent intent = new Intent(getActivity(), + XposedBaseActivity.class); startActivity(intent); } }); diff --git a/app/src/main/java/de/robv/android/xposed/installer/WelcomeActivity.java b/app/src/main/java/de/robv/android/xposed/installer/WelcomeActivity.java index ffb5ffa05..ec3903b31 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/WelcomeActivity.java +++ b/app/src/main/java/de/robv/android/xposed/installer/WelcomeActivity.java @@ -22,13 +22,12 @@ import de.robv.android.xposed.installer.util.RepoLoader.RepoListener; import de.robv.android.xposed.installer.util.ThemeUtil; -public class WelcomeActivity extends XposedBaseActivity implements - NavigationView.OnNavigationItemSelectedListener, ModuleListener, RepoListener { - - private RepoLoader mRepoLoader; +public class WelcomeActivity extends XposedBaseActivity + implements NavigationView.OnNavigationItemSelectedListener, + ModuleListener, RepoListener { private static final String SELECTED_ITEM_ID = "SELECTED_ITEM_ID"; - + private RepoLoader mRepoLoader; private Toolbar mToolbar; private DrawerLayout mDrawerLayout; private NavigationView mNavigationView; @@ -48,18 +47,20 @@ protected void onCreate(Bundle savedInstanceState) { mNavigationView = (NavigationView) findViewById(R.id.navigation_view); mNavigationView.setNavigationItemSelectedListener(this); - mDrawerToggle = new ActionBarDrawerToggle(this, - mDrawerLayout, - mToolbar, + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); mDrawerLayout.setDrawerListener(mDrawerToggle); - mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.colorPrimaryDark)); + mDrawerLayout.setStatusBarBackgroundColor( + getResources().getColor(R.color.colorPrimaryDark)); mDrawerToggle.syncState(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - mSelectedId = mNavigationView.getMenu().getItem(prefs.getInt("default_view", 0)).getItemId(); - mSelectedId = savedInstanceState == null ? mSelectedId : savedInstanceState.getInt(SELECTED_ITEM_ID); + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(this); + mSelectedId = mNavigationView.getMenu() + .getItem(prefs.getInt("default_view", 0)).getItemId(); + mSelectedId = savedInstanceState == null ? mSelectedId + : savedInstanceState.getInt(SELECTED_ITEM_ID); mNavigationView.getMenu().findItem(mSelectedId).setChecked(true); if (savedInstanceState == null) { @@ -110,7 +111,8 @@ private void navigate(final int itemId) { } if (navFragment != null) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + FragmentTransaction transaction = getSupportFragmentManager() + .beginTransaction(); transaction.replace(R.id.content_frame, navFragment).commit(); } } @@ -144,18 +146,20 @@ private void notifyDataSetChanged() { String frameworkUpdateVersion = mRepoLoader.getFrameworkUpdateVersion(); boolean moduleUpdateAvailable = mRepoLoader.hasModuleUpdates(); - Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.content_frame); + Fragment currentFragment = getSupportFragmentManager() + .findFragmentById(R.id.content_frame); if (currentFragment instanceof DownloadDetailsFragment) { if (frameworkUpdateVersion != null) { Snackbar.make(parentLayout, - R.string.welcome_framework_update_available + " " + - String.valueOf(frameworkUpdateVersion), + R.string.welcome_framework_update_available + " " + + String.valueOf(frameworkUpdateVersion), Snackbar.LENGTH_LONG).show(); } } if (moduleUpdateAvailable) { - Snackbar.make(parentLayout, R.string.modules_updates_available, Snackbar.LENGTH_LONG) + Snackbar.make(parentLayout, R.string.modules_updates_available, + Snackbar.LENGTH_LONG) .setAction("VIEW", new View.OnClickListener() { @Override public void onClick(View view) { @@ -171,7 +175,8 @@ public void onInstalledModulesReloaded(ModuleUtil moduleUtil) { } @Override - public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, InstalledModule module) { + public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, + String packageName, InstalledModule module) { notifyDataSetChanged(); } diff --git a/app/src/main/java/de/robv/android/xposed/installer/XposedApp.java b/app/src/main/java/de/robv/android/xposed/installer/XposedApp.java index a9eb445ae..4dc6a8692 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/XposedApp.java +++ b/app/src/main/java/de/robv/android/xposed/installer/XposedApp.java @@ -1,15 +1,5 @@ package de.robv.android.xposed.installer; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; @@ -23,17 +13,30 @@ import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + import de.robv.android.xposed.installer.util.AssetUtil; import de.robv.android.xposed.installer.util.ModuleUtil; import de.robv.android.xposed.installer.util.NotificationUtil; import de.robv.android.xposed.installer.util.RepoLoader; -public class XposedApp extends Application implements ActivityLifecycleCallbacks { +public class XposedApp extends Application + implements ActivityLifecycleCallbacks { public static final String TAG = "XposedInstaller"; @SuppressLint("SdCardPath") public static final String BASE_DIR = "/data/data/de.robv.android.xposed.installer/"; - private static final File XPOSED_PROP_FILE = new File("/system/xposed.prop"); + private static final File XPOSED_PROP_FILE = new File( + "/system/xposed.prop"); private static XposedApp mInstance = null; private static Thread mUiThread; @@ -44,6 +47,33 @@ public class XposedApp extends Application implements ActivityLifecycleCallbacks private SharedPreferences mPref; private Map mXposedProp; + public static XposedApp getInstance() { + return mInstance; + } + + public static void runOnUiThread(Runnable action) { + if (Thread.currentThread() != mUiThread) { + mMainHandler.post(action); + } else { + action.run(); + } + } + + // This method is hooked by XposedBridge to return the current version + public static int getActiveXposedVersion() { + return -1; + } + + public static Map getXposedProp() { + synchronized (mInstance) { + return mInstance.mXposedProp; + } + } + + public static SharedPreferences getPreferences() { + return mInstance.mPref; + } + public void onCreate() { super.onCreate(); mInstance = this; @@ -69,7 +99,8 @@ private void createDirectories() { private void cleanup() { if (!mPref.getBoolean("cleaned_up_sdcard", false)) { - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + if (Environment.getExternalStorageState() + .equals(Environment.MEDIA_MOUNTED)) { File sdcard = Environment.getExternalStorageDirectory(); new File(sdcard, "Xposed-Disabler-CWM.zip").delete(); new File(sdcard, "Xposed-Disabler-Recovery.zip").delete(); @@ -91,23 +122,6 @@ private void mkdirAndChmod(String dir, int permissions) { FileUtils.setPermissions(dir, permissions, -1, -1); } - public static XposedApp getInstance() { - return mInstance; - } - - public static void runOnUiThread(Runnable action) { - if (Thread.currentThread() != mUiThread) { - mMainHandler.post(action); - } else { - action.run(); - } - } - - // This method is hooked by XposedBridge to return the current version - public static int getActiveXposedVersion() { - return -1; - } - private void reloadXposedProp() { Map map = Collections.emptyMap(); if (XPOSED_PROP_FILE.canRead()) { @@ -116,12 +130,14 @@ private void reloadXposedProp() { is = new FileInputStream(XPOSED_PROP_FILE); map = parseXposedProp(is); } catch (IOException e) { - Log.e(XposedApp.TAG, "Could not read " + XPOSED_PROP_FILE.getPath(), e); + Log.e(XposedApp.TAG, + "Could not read " + XPOSED_PROP_FILE.getPath(), e); } finally { if (is != null) { try { is.close(); - } catch (IOException ignored) {} + } catch (IOException ignored) { + } } } } @@ -131,8 +147,10 @@ private void reloadXposedProp() { } } - private Map parseXposedProp(InputStream stream) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + private Map parseXposedProp(InputStream stream) + throws IOException { + BufferedReader reader = new BufferedReader( + new InputStreamReader(stream)); Map map = new LinkedHashMap(); String line; while ((line = reader.readLine()) != null) { @@ -149,41 +167,33 @@ private Map parseXposedProp(InputStream stream) throws IOExcepti return Collections.unmodifiableMap(map); } - public static Map getXposedProp() { - synchronized (mInstance) { - return mInstance.mXposedProp; - } - } - public boolean areDownloadsEnabled() { if (!mPref.getBoolean("enable_downloads", true)) return false; - if (checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) - return false; + return checkCallingOrSelfPermission( + Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED; - return true; - } - - public static SharedPreferences getPreferences() { - return mInstance.mPref; } public void updateProgressIndicator() { - final boolean isLoading = RepoLoader.getInstance().isLoading() || ModuleUtil.getInstance().isLoading(); + final boolean isLoading = RepoLoader.getInstance().isLoading() + || ModuleUtil.getInstance().isLoading(); runOnUiThread(new Runnable() { @Override public void run() { synchronized (XposedApp.this) { if (mCurrentActivity != null) - mCurrentActivity.setProgressBarIndeterminateVisibility(isLoading); + mCurrentActivity.setProgressBarIndeterminateVisibility( + isLoading); } } }); } @Override - public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) { + public synchronized void onActivityCreated(Activity activity, + Bundle savedInstanceState) { if (mIsUiLoaded) return; @@ -203,8 +213,20 @@ public synchronized void onActivityPaused(Activity activity) { mCurrentActivity = null; } - @Override public void onActivityStarted(Activity activity) {} - @Override public void onActivityStopped(Activity activity) {} - @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} - @Override public void onActivityDestroyed(Activity activity) {} + @Override + public void onActivityStarted(Activity activity) { + } + + @Override + public void onActivityStopped(Activity activity) { + } + + @Override + public void onActivitySaveInstanceState(Activity activity, + Bundle outState) { + } + + @Override + public void onActivityDestroyed(Activity activity) { + } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/Module.java b/app/src/main/java/de/robv/android/xposed/installer/repo/Module.java index 8d416a4b3..d1f5b7185 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/Module.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/Module.java @@ -1,13 +1,16 @@ package de.robv.android.xposed.installer.repo; +import android.util.Pair; + import java.util.ArrayList; import java.util.LinkedList; import java.util.List; -import android.util.Pair; - public class Module { public final Repository repository; + public final List> moreInfo = new LinkedList>(); + public final List versions = new ArrayList(); + public final List screenshots = new ArrayList(); public String packageName; public String name; public String summary; @@ -15,13 +18,10 @@ public class Module { public boolean descriptionIsHtml = false; public String author; public String support; - public final List> moreInfo = new LinkedList>(); - public final List versions = new ArrayList(); - public final List screenshots = new ArrayList(); public long created = -1; public long updated = -1; - /*package*/ Module(Repository repository) { + /* package */ Module(Repository repository) { this.repository = repository; } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/ModuleVersion.java b/app/src/main/java/de/robv/android/xposed/installer/repo/ModuleVersion.java index 082fbb21a..96f67c11b 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/ModuleVersion.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/ModuleVersion.java @@ -1,6 +1,5 @@ package de.robv.android.xposed.installer.repo; - public class ModuleVersion { public final Module module; public String name; @@ -12,7 +11,7 @@ public class ModuleVersion { public ReleaseType relType = ReleaseType.STABLE; public long uploaded = -1; - /*package*/ ModuleVersion(Module module) { + /* package */ ModuleVersion(Module module) { this.module = module; } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/ReleaseType.java b/app/src/main/java/de/robv/android/xposed/installer/repo/ReleaseType.java index 7ef1bf2d9..c68164f6e 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/ReleaseType.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/ReleaseType.java @@ -3,11 +3,19 @@ import de.robv.android.xposed.installer.R; public enum ReleaseType { - 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); + 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); private static final ReleaseType[] sValuesCache = values(); + private final int mTitleId; + private final int mSummaryId; + + ReleaseType(int titleId, int summaryId) { + mTitleId = titleId; + mSummaryId = summaryId; + } public static ReleaseType fromString(String value) { if (value == null || value.equals("stable")) @@ -24,14 +32,6 @@ public static ReleaseType fromOrdinal(int ordinal) { return sValuesCache[ordinal]; } - private final int mTitleId; - private final int mSummaryId; - - private ReleaseType(int titleId, int summaryId) { - mTitleId = titleId; - mSummaryId = summaryId; - } - public int getTitleId() { return mTitleId; } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDb.java b/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDb.java index 6b6245acf..656d59e23 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDb.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDb.java @@ -1,9 +1,5 @@ package de.robv.android.xposed.installer.repo; -import java.io.File; -import java.util.LinkedHashMap; -import java.util.Map; - import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -11,6 +7,11 @@ import android.database.sqlite.SQLiteOpenHelper; import android.text.TextUtils; import android.util.Pair; + +import java.io.File; +import java.util.LinkedHashMap; +import java.util.Map; + import de.robv.android.xposed.installer.repo.RepoDbDefinitions.InstalledModulesColumns; import de.robv.android.xposed.installer.repo.RepoDbDefinitions.InstalledModulesUpdatesColumns; import de.robv.android.xposed.installer.repo.RepoDbDefinitions.ModuleVersionsColumns; @@ -32,9 +33,18 @@ public final class RepoDb extends SQLiteOpenHelper { private static SQLiteDatabase mDb; private static RepoLoader mRepoLoader; - public synchronized static void init(Context context, RepoLoader repoLoader) { + private RepoDb(Context context) { + super(context, + new File(context.getCacheDir(), RepoDbDefinitions.DATABASE_NAME) + .getPath(), + null, RepoDbDefinitions.DATABASE_VERSION); + } + + public synchronized static void init(Context context, + RepoLoader repoLoader) { if (mInstance != null) - throw new IllegalStateException(RepoDb.class.getSimpleName() + " is already initialized"); + throw new IllegalStateException( + RepoDb.class.getSimpleName() + " is already initialized"); mRepoLoader = repoLoader; mInstance = new RepoDb(context); @@ -43,46 +53,6 @@ public synchronized static void init(Context context, RepoLoader repoLoader) { mInstance.createTempTables(mDb); } - private RepoDb(Context context) { - super(context, new File(context.getCacheDir(), RepoDbDefinitions.DATABASE_NAME).getPath(), - null, RepoDbDefinitions.DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_REPOSITORIES); - db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_MODULES); - db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_MODULE_VERSIONS); - db.execSQL(RepoDbDefinitions.SQL_CREATE_INDEX_MODULE_VERSIONS_MODULE_ID); - db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_MORE_INFO); - - mRepoLoader.clear(false); - } - - private void createTempTables(SQLiteDatabase db) { - db.execSQL(RepoDbDefinitions.SQL_CREATE_TEMP_TABLE_INSTALLED_MODULES); - db.execSQL(RepoDbDefinitions.SQL_CREATE_TEMP_VIEW_INSTALLED_MODULES_UPDATES); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // This is only a cache, so simply drop & recreate the tables - db.execSQL("DROP TABLE IF EXISTS " + RepositoriesColumns.TABLE_NAME); - db.execSQL("DROP TABLE IF EXISTS " + ModulesColumns.TABLE_NAME); - db.execSQL("DROP TABLE IF EXISTS " + ModuleVersionsColumns.TABLE_NAME); - db.execSQL("DROP TABLE IF EXISTS " + MoreInfoColumns.TABLE_NAME); - - db.execSQL("DROP TABLE IF EXISTS " + InstalledModulesColumns.TABLE_NAME); - db.execSQL("DROP VIEW IF EXISTS " + InstalledModulesUpdatesColumns.VIEW_NAME); - - onCreate(db); - } - - @Override - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - onUpgrade(db, oldVersion, newVersion); - } - public static void beginTransation() { mDb.beginTransaction(); } @@ -95,19 +65,21 @@ public static void endTransation() { mDb.endTransaction(); } - private static String getString(String table, String searchColumn, String searchValue, String resultColumn) { + private static String getString(String table, String searchColumn, + String searchValue, String resultColumn) { String[] projection = new String[] { resultColumn }; String where = searchColumn + " = ?"; String[] whereArgs = new String[] { searchValue }; - Cursor c = mDb.query(table, projection, where, whereArgs, null, null, null, "1"); + Cursor c = mDb.query(table, projection, where, whereArgs, null, null, + null, "1"); if (c.moveToFirst()) { String result = c.getString(c.getColumnIndexOrThrow(resultColumn)); c.close(); return result; } else { c.close(); - throw new RowNotFoundException("Could not find " + table + "." + searchColumn - + " with value '" + searchValue + "'"); + throw new RowNotFoundException("Could not find " + table + "." + + searchColumn + " with value '" + searchValue + "'"); } } @@ -122,25 +94,27 @@ public static void deleteRepositories() { mDb.delete(RepositoriesColumns.TABLE_NAME, null, null); } - public static Map getRepositories() { - Map result = new LinkedHashMap(1); + public static Map getRepositories() { + Map result = new LinkedHashMap(1); - String[] projection = new String[] { - RepositoriesColumns._ID, - RepositoriesColumns.URL, - RepositoriesColumns.TITLE, - RepositoriesColumns.PARTIAL_URL, - RepositoriesColumns.VERSION, - }; - - Cursor c = mDb.query(RepositoriesColumns.TABLE_NAME, projection, null, null, null, null, RepositoriesColumns._ID); + String[] projection = new String[] { RepositoriesColumns._ID, + RepositoriesColumns.URL, RepositoriesColumns.TITLE, + RepositoriesColumns.PARTIAL_URL, RepositoriesColumns.VERSION, }; + + Cursor c = mDb.query(RepositoriesColumns.TABLE_NAME, projection, null, + null, null, null, RepositoriesColumns._ID); while (c.moveToNext()) { Repository repo = new Repository(); - long id = c.getLong(c.getColumnIndexOrThrow(RepositoriesColumns._ID)); - repo.url = c.getString(c.getColumnIndexOrThrow(RepositoriesColumns.URL)); - repo.name = c.getString(c.getColumnIndexOrThrow(RepositoriesColumns.TITLE)); - repo.partialUrl = c.getString(c.getColumnIndexOrThrow(RepositoriesColumns.PARTIAL_URL)); - repo.version = c.getString(c.getColumnIndexOrThrow(RepositoriesColumns.VERSION)); + long id = c + .getLong(c.getColumnIndexOrThrow(RepositoriesColumns._ID)); + repo.url = c.getString( + c.getColumnIndexOrThrow(RepositoriesColumns.URL)); + repo.name = c.getString( + c.getColumnIndexOrThrow(RepositoriesColumns.TITLE)); + repo.partialUrl = c.getString( + c.getColumnIndexOrThrow(RepositoriesColumns.PARTIAL_URL)); + repo.version = c.getString( + c.getColumnIndexOrThrow(RepositoriesColumns.VERSION)); result.put(id, repo); } @@ -184,7 +158,8 @@ public static long insertModule(long repoId, Module mod) { mDb.beginTransaction(); try { - long moduleId = mDb.insertOrThrow(ModulesColumns.TABLE_NAME, null, values); + long moduleId = mDb.insertOrThrow(ModulesColumns.TABLE_NAME, null, + values); long latestVersionId = -1; for (ModuleVersion version : mod.versions) { @@ -201,8 +176,9 @@ public static long insertModule(long repoId, Module mod) { new String[] { Long.toString(moduleId) }); } - for (Pair moreInfoEntry : mod.moreInfo) { - insertMoreInfo(moduleId, moreInfoEntry.first, moreInfoEntry.second); + for (Pair moreInfoEntry : mod.moreInfo) { + insertMoreInfo(moduleId, moreInfoEntry.first, + moreInfoEntry.second); } // TODO Add mod.screenshots @@ -215,7 +191,8 @@ public static long insertModule(long repoId, Module mod) { } } - private static long insertModuleVersion(long moduleId, ModuleVersion version) { + private static long insertModuleVersion(long moduleId, + ModuleVersion version) { ContentValues values = new ContentValues(); values.put(ModuleVersionsColumns.MODULE_ID, moduleId); values.put(ModuleVersionsColumns.NAME, version.name); @@ -223,13 +200,16 @@ private static long insertModuleVersion(long moduleId, ModuleVersion version) { values.put(ModuleVersionsColumns.DOWNLOAD_LINK, version.downloadLink); values.put(ModuleVersionsColumns.MD5SUM, version.md5sum); values.put(ModuleVersionsColumns.CHANGELOG, version.changelog); - values.put(ModuleVersionsColumns.CHANGELOG_IS_HTML, version.changelogIsHtml); + values.put(ModuleVersionsColumns.CHANGELOG_IS_HTML, + version.changelogIsHtml); values.put(ModuleVersionsColumns.RELTYPE, version.relType.ordinal()); values.put(ModuleVersionsColumns.UPLOADED, version.uploaded); - return mDb.insertOrThrow(ModuleVersionsColumns.TABLE_NAME, null, values); + return mDb.insertOrThrow(ModuleVersionsColumns.TABLE_NAME, null, + values); } - private static long insertMoreInfo(long moduleId, String title, String value) { + private static long insertMoreInfo(long moduleId, String title, + String value) { ContentValues values = new ContentValues(); values.put(MoreInfoColumns.MODULE_ID, moduleId); values.put(MoreInfoColumns.LABEL, title); @@ -238,103 +218,111 @@ private static long insertMoreInfo(long moduleId, String title, String value) { } public static void deleteAllModules(long repoId) { - mDb.delete(ModulesColumns.TABLE_NAME, - ModulesColumns.REPO_ID + " = ?", + mDb.delete(ModulesColumns.TABLE_NAME, ModulesColumns.REPO_ID + " = ?", new String[] { Long.toString(repoId) }); } public static void deleteModule(long repoId, String packageName) { mDb.delete(ModulesColumns.TABLE_NAME, - ModulesColumns.REPO_ID + " = ? AND " + ModulesColumns.PKGNAME + " = ?", + ModulesColumns.REPO_ID + " = ? AND " + ModulesColumns.PKGNAME + + " = ?", new String[] { Long.toString(repoId), packageName }); } public static Module getModuleByPackageName(String packageName) { // The module itself - String[] projection = new String[] { - ModulesColumns._ID, - ModulesColumns.REPO_ID, - ModulesColumns.PKGNAME, - ModulesColumns.TITLE, - ModulesColumns.SUMMARY, - ModulesColumns.DESCRIPTION, - ModulesColumns.DESCRIPTION_IS_HTML, - ModulesColumns.AUTHOR, - ModulesColumns.SUPPORT, - ModulesColumns.CREATED, - ModulesColumns.UPDATED, - }; - - String where = ModulesColumns.PREFERRED + " = 1 AND " + ModulesColumns.PKGNAME + " = ?"; + String[] projection = new String[] { ModulesColumns._ID, + ModulesColumns.REPO_ID, ModulesColumns.PKGNAME, + ModulesColumns.TITLE, ModulesColumns.SUMMARY, + ModulesColumns.DESCRIPTION, ModulesColumns.DESCRIPTION_IS_HTML, + ModulesColumns.AUTHOR, ModulesColumns.SUPPORT, + ModulesColumns.CREATED, ModulesColumns.UPDATED, }; + + String where = ModulesColumns.PREFERRED + " = 1 AND " + + ModulesColumns.PKGNAME + " = ?"; String[] whereArgs = new String[] { packageName }; - Cursor c = mDb.query(ModulesColumns.TABLE_NAME, projection, where, whereArgs, null, null, null, "1"); + Cursor c = mDb.query(ModulesColumns.TABLE_NAME, projection, where, + whereArgs, null, null, null, "1"); if (!c.moveToFirst()) { c.close(); return null; } long moduleId = c.getLong(c.getColumnIndexOrThrow(ModulesColumns._ID)); - long repoId = c.getLong(c.getColumnIndexOrThrow(ModulesColumns.REPO_ID)); + long repoId = c + .getLong(c.getColumnIndexOrThrow(ModulesColumns.REPO_ID)); Module mod = new Module(mRepoLoader.getRepository(repoId)); - mod.packageName = c.getString(c.getColumnIndexOrThrow(ModulesColumns.PKGNAME)); + mod.packageName = c + .getString(c.getColumnIndexOrThrow(ModulesColumns.PKGNAME)); mod.name = c.getString(c.getColumnIndexOrThrow(ModulesColumns.TITLE)); - mod.summary = c.getString(c.getColumnIndexOrThrow(ModulesColumns.SUMMARY)); - mod.description = c.getString(c.getColumnIndexOrThrow(ModulesColumns.DESCRIPTION)); - mod.descriptionIsHtml = c.getInt(c.getColumnIndexOrThrow(ModulesColumns.DESCRIPTION_IS_HTML)) > 0; - mod.author = c.getString(c.getColumnIndexOrThrow(ModulesColumns.AUTHOR)); - mod.support = c.getString(c.getColumnIndexOrThrow(ModulesColumns.SUPPORT)); - mod.created = c.getLong(c.getColumnIndexOrThrow(ModulesColumns.CREATED)); - mod.updated = c.getLong(c.getColumnIndexOrThrow(ModulesColumns.UPDATED)); + mod.summary = c + .getString(c.getColumnIndexOrThrow(ModulesColumns.SUMMARY)); + mod.description = c + .getString(c.getColumnIndexOrThrow(ModulesColumns.DESCRIPTION)); + mod.descriptionIsHtml = c.getInt(c + .getColumnIndexOrThrow(ModulesColumns.DESCRIPTION_IS_HTML)) > 0; + mod.author = c + .getString(c.getColumnIndexOrThrow(ModulesColumns.AUTHOR)); + mod.support = c + .getString(c.getColumnIndexOrThrow(ModulesColumns.SUPPORT)); + mod.created = c + .getLong(c.getColumnIndexOrThrow(ModulesColumns.CREATED)); + mod.updated = c + .getLong(c.getColumnIndexOrThrow(ModulesColumns.UPDATED)); c.close(); - // Versions - projection = new String[] { - ModuleVersionsColumns.NAME, - ModuleVersionsColumns.CODE, - ModuleVersionsColumns.DOWNLOAD_LINK, - ModuleVersionsColumns.MD5SUM, - ModuleVersionsColumns.CHANGELOG, - ModuleVersionsColumns.CHANGELOG_IS_HTML, - ModuleVersionsColumns.RELTYPE, - ModuleVersionsColumns.UPLOADED, - }; + projection = new String[] { ModuleVersionsColumns.NAME, + ModuleVersionsColumns.CODE, ModuleVersionsColumns.DOWNLOAD_LINK, + ModuleVersionsColumns.MD5SUM, ModuleVersionsColumns.CHANGELOG, + ModuleVersionsColumns.CHANGELOG_IS_HTML, + ModuleVersionsColumns.RELTYPE, + ModuleVersionsColumns.UPLOADED, }; where = ModuleVersionsColumns.MODULE_ID + " = ?"; whereArgs = new String[] { Long.toString(moduleId) }; - c = mDb.query(ModuleVersionsColumns.TABLE_NAME, projection, where, whereArgs, null, null, null); + c = mDb.query(ModuleVersionsColumns.TABLE_NAME, projection, where, + whereArgs, null, null, null); while (c.moveToNext()) { ModuleVersion version = new ModuleVersion(mod); - version.name = c.getString(c.getColumnIndexOrThrow(ModuleVersionsColumns.NAME)); - version.code = c.getInt(c.getColumnIndexOrThrow(ModuleVersionsColumns.CODE)); - version.downloadLink = c.getString(c.getColumnIndexOrThrow(ModuleVersionsColumns.DOWNLOAD_LINK)); - version.md5sum = c.getString(c.getColumnIndexOrThrow(ModuleVersionsColumns.MD5SUM)); - version.changelog = c.getString(c.getColumnIndexOrThrow(ModuleVersionsColumns.CHANGELOG)); - version.changelogIsHtml = c.getInt(c.getColumnIndexOrThrow(ModuleVersionsColumns.CHANGELOG_IS_HTML)) > 0; - version.relType = ReleaseType.fromOrdinal(c.getInt(c.getColumnIndexOrThrow(ModuleVersionsColumns.RELTYPE))); - version.uploaded = c.getLong(c.getColumnIndexOrThrow(ModuleVersionsColumns.UPLOADED)); + version.name = c.getString( + c.getColumnIndexOrThrow(ModuleVersionsColumns.NAME)); + version.code = c.getInt( + c.getColumnIndexOrThrow(ModuleVersionsColumns.CODE)); + version.downloadLink = c.getString(c.getColumnIndexOrThrow( + ModuleVersionsColumns.DOWNLOAD_LINK)); + version.md5sum = c.getString( + c.getColumnIndexOrThrow(ModuleVersionsColumns.MD5SUM)); + version.changelog = c.getString( + c.getColumnIndexOrThrow(ModuleVersionsColumns.CHANGELOG)); + version.changelogIsHtml = c.getInt(c.getColumnIndexOrThrow( + ModuleVersionsColumns.CHANGELOG_IS_HTML)) > 0; + version.relType = ReleaseType.fromOrdinal(c.getInt( + c.getColumnIndexOrThrow(ModuleVersionsColumns.RELTYPE))); + version.uploaded = c.getLong( + c.getColumnIndexOrThrow(ModuleVersionsColumns.UPLOADED)); mod.versions.add(version); } c.close(); - // MoreInfo - projection = new String[] { - MoreInfoColumns.LABEL, - MoreInfoColumns.VALUE, - }; + projection = new String[] { MoreInfoColumns.LABEL, + MoreInfoColumns.VALUE, }; where = MoreInfoColumns.MODULE_ID + " = ?"; whereArgs = new String[] { Long.toString(moduleId) }; - c = mDb.query(MoreInfoColumns.TABLE_NAME, projection, where, whereArgs, null, null, MoreInfoColumns._ID); + c = mDb.query(MoreInfoColumns.TABLE_NAME, projection, where, whereArgs, + null, null, MoreInfoColumns._ID); while (c.moveToNext()) { - String label = c.getString(c.getColumnIndexOrThrow(MoreInfoColumns.LABEL)); - String value = c.getString(c.getColumnIndexOrThrow(MoreInfoColumns.VALUE)); + String label = c + .getString(c.getColumnIndexOrThrow(MoreInfoColumns.LABEL)); + String value = c + .getString(c.getColumnIndexOrThrow(MoreInfoColumns.VALUE)); mod.moreInfo.add(new Pair(label, value)); } c.close(); @@ -343,26 +331,31 @@ public static Module getModuleByPackageName(String packageName) { } public static String getModuleSupport(String packageName) { - return getString(ModulesColumns.TABLE_NAME, ModulesColumns.PKGNAME, packageName, ModulesColumns.SUPPORT); + return getString(ModulesColumns.TABLE_NAME, ModulesColumns.PKGNAME, + packageName, ModulesColumns.SUPPORT); } public static void updateModuleLatestVersion(String packageName) { - int maxShownReleaseType = mRepoLoader.getMaxShownReleaseType(packageName).ordinal(); - mDb.execSQL("UPDATE " + ModulesColumns.TABLE_NAME - + " SET " + ModulesColumns.LATEST_VERSION - + " = (SELECT " + ModuleVersionsColumns._ID + " FROM " + ModuleVersionsColumns.TABLE_NAME + " AS v" - + " WHERE v." + ModuleVersionsColumns.MODULE_ID - + " = " + ModulesColumns.TABLE_NAME + "." + ModulesColumns._ID - + " AND reltype <= ? LIMIT 1)" - + " WHERE " + ModulesColumns.PKGNAME + " = ?", - new Object[] { maxShownReleaseType, packageName }); + int maxShownReleaseType = mRepoLoader + .getMaxShownReleaseType(packageName).ordinal(); + mDb.execSQL( + "UPDATE " + ModulesColumns.TABLE_NAME + " SET " + + ModulesColumns.LATEST_VERSION + " = (SELECT " + + ModuleVersionsColumns._ID + " FROM " + + ModuleVersionsColumns.TABLE_NAME + " AS v" + + " WHERE v." + ModuleVersionsColumns.MODULE_ID + " = " + + ModulesColumns.TABLE_NAME + "." + ModulesColumns._ID + + " AND reltype <= ? LIMIT 1)" + " WHERE " + + ModulesColumns.PKGNAME + " = ?", + new Object[] { maxShownReleaseType, packageName }); } public static void updateAllModulesLatestVersion() { mDb.beginTransaction(); try { String[] projection = new String[] { ModulesColumns.PKGNAME }; - Cursor c = mDb.query(true, ModulesColumns.TABLE_NAME, projection, null, null, null, null, null, null); + Cursor c = mDb.query(true, ModulesColumns.TABLE_NAME, projection, + null, null, null, null, null, null); while (c.moveToNext()) { updateModuleLatestVersion(c.getString(0)); } @@ -378,7 +371,8 @@ public static long insertInstalledModule(InstalledModule installed) { values.put(InstalledModulesColumns.PKGNAME, installed.packageName); values.put(InstalledModulesColumns.VERSION_CODE, installed.versionCode); values.put(InstalledModulesColumns.VERSION_NAME, installed.versionName); - return mDb.insertOrThrow(InstalledModulesColumns.TABLE_NAME, null, values); + return mDb.insertOrThrow(InstalledModulesColumns.TABLE_NAME, null, + values); } public static void deleteInstalledModule(String packageName) { @@ -391,40 +385,45 @@ public static void deleteAllInstalledModules() { mDb.delete(InstalledModulesColumns.TABLE_NAME, null, null); } - public static Cursor queryModuleOverview(int sortingOrder, CharSequence filterText) { + public static Cursor queryModuleOverview(int sortingOrder, + CharSequence filterText) { // Columns - String[] projection = new String[] { - "m." + ModulesColumns._ID, - "m." + ModulesColumns.PKGNAME, - "m." + ModulesColumns.TITLE, - "m." + ModulesColumns.SUMMARY, - "m." + ModulesColumns.CREATED, - "m." + ModulesColumns.UPDATED, - - "v." + ModuleVersionsColumns.NAME + " AS " + OverviewColumns.LATEST_VERSION, - "i." + InstalledModulesColumns.VERSION_NAME + " AS " + OverviewColumns.INSTALLED_VERSION, - - "(CASE WHEN m." + ModulesColumns.PKGNAME + " = '" + ModuleUtil.getInstance().getFrameworkPackageName() - + "' THEN 1 ELSE 0 END) AS " + OverviewColumns.IS_FRAMEWORK, - - "(CASE WHEN i." + InstalledModulesColumns.VERSION_NAME + " IS NOT NULL" - + " THEN 1 ELSE 0 END) AS " + OverviewColumns.IS_INSTALLED, - - "(CASE WHEN v." + ModuleVersionsColumns.CODE + " > " + InstalledModulesColumns.VERSION_CODE - + " THEN 1 ELSE 0 END) AS " + OverviewColumns.HAS_UPDATE, - }; + String[] projection = new String[] { "m." + ModulesColumns._ID, + "m." + ModulesColumns.PKGNAME, "m." + ModulesColumns.TITLE, + "m." + ModulesColumns.SUMMARY, "m." + ModulesColumns.CREATED, + "m." + ModulesColumns.UPDATED, + + "v." + ModuleVersionsColumns.NAME + " AS " + + OverviewColumns.LATEST_VERSION, + "i." + InstalledModulesColumns.VERSION_NAME + " AS " + + OverviewColumns.INSTALLED_VERSION, + + "(CASE WHEN m." + ModulesColumns.PKGNAME + " = '" + + ModuleUtil.getInstance().getFrameworkPackageName() + + "' THEN 1 ELSE 0 END) AS " + + OverviewColumns.IS_FRAMEWORK, + + "(CASE WHEN i." + InstalledModulesColumns.VERSION_NAME + + " IS NOT NULL" + " THEN 1 ELSE 0 END) AS " + + OverviewColumns.IS_INSTALLED, + + "(CASE WHEN v." + ModuleVersionsColumns.CODE + " > " + + InstalledModulesColumns.VERSION_CODE + + " THEN 1 ELSE 0 END) AS " + + OverviewColumns.HAS_UPDATE, }; // Conditions String where = ModulesColumns.PREFERRED + " = 1"; String whereArgs[] = null; if (!TextUtils.isEmpty(filterText)) { - where += " AND (m." + ModulesColumns.TITLE + " LIKE ?" - + " OR m." + ModulesColumns.SUMMARY + " LIKE ?" - + " OR m." + ModulesColumns.DESCRIPTION + " LIKE ?" - + " OR m." + ModulesColumns.AUTHOR + " LIKE ?)"; + where += " AND (m." + ModulesColumns.TITLE + " LIKE ?" + " OR m." + + ModulesColumns.SUMMARY + " LIKE ?" + " OR m." + + ModulesColumns.DESCRIPTION + " LIKE ?" + " OR m." + + ModulesColumns.AUTHOR + " LIKE ?)"; String filterTextArg = "%" + filterText + "%"; - whereArgs = new String[] { filterTextArg, filterTextArg, filterTextArg, filterTextArg }; + whereArgs = new String[] { filterTextArg, filterTextArg, + filterTextArg, filterTextArg }; } // Sorting order @@ -450,12 +449,14 @@ public static Cursor queryModuleOverview(int sortingOrder, CharSequence filterTe // Query Cursor c = mDb.query( - ModulesColumns.TABLE_NAME + " AS m" + - " LEFT JOIN " + ModuleVersionsColumns.TABLE_NAME + " AS v" + - " ON v." + ModuleVersionsColumns._ID + " = m." + ModulesColumns.LATEST_VERSION + - " LEFT JOIN " + InstalledModulesColumns.TABLE_NAME + " AS i" + - " ON i." + InstalledModulesColumns.PKGNAME + " = m." + ModulesColumns.PKGNAME, - projection, where, whereArgs, null, null, sbOrder.toString()); + ModulesColumns.TABLE_NAME + " AS m" + " LEFT JOIN " + + ModuleVersionsColumns.TABLE_NAME + " AS v" + " ON v." + + ModuleVersionsColumns._ID + " = m." + + ModulesColumns.LATEST_VERSION + " LEFT JOIN " + + InstalledModulesColumns.TABLE_NAME + " AS i" + + " ON i." + InstalledModulesColumns.PKGNAME + " = m." + + ModulesColumns.PKGNAME, + projection, where, whereArgs, null, null, sbOrder.toString()); // Cache column indexes OverviewColumnsIndexes.fillFromCursor(c); @@ -472,20 +473,63 @@ public static boolean hasModuleUpdates() { } private static String getFirstUpdate(boolean framework) { - String[] projection = new String[] { InstalledModulesUpdatesColumns.LATEST_NAME }; + String[] projection = new String[] { + InstalledModulesUpdatesColumns.LATEST_NAME }; String where = ModulesColumns.PKGNAME + (framework ? " = ?" : " != ?"); - String[] whereArgs = new String[] { ModuleUtil.getInstance().getFrameworkPackageName() }; - Cursor c = mDb.query(InstalledModulesUpdatesColumns.VIEW_NAME, projection, where, whereArgs, null, null, null, "1"); + String[] whereArgs = new String[] { + ModuleUtil.getInstance().getFrameworkPackageName() }; + Cursor c = mDb.query(InstalledModulesUpdatesColumns.VIEW_NAME, + projection, where, whereArgs, null, null, null, "1"); String latestVersion = null; if (c.moveToFirst()) - latestVersion = c.getString(c.getColumnIndexOrThrow(InstalledModulesUpdatesColumns.LATEST_NAME)); + latestVersion = c.getString(c.getColumnIndexOrThrow( + InstalledModulesUpdatesColumns.LATEST_NAME)); c.close(); return latestVersion; } + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_REPOSITORIES); + db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_MODULES); + db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_MODULE_VERSIONS); + db.execSQL( + RepoDbDefinitions.SQL_CREATE_INDEX_MODULE_VERSIONS_MODULE_ID); + db.execSQL(RepoDbDefinitions.SQL_CREATE_TABLE_MORE_INFO); + + mRepoLoader.clear(false); + } + + private void createTempTables(SQLiteDatabase db) { + db.execSQL(RepoDbDefinitions.SQL_CREATE_TEMP_TABLE_INSTALLED_MODULES); + db.execSQL( + RepoDbDefinitions.SQL_CREATE_TEMP_VIEW_INSTALLED_MODULES_UPDATES); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // This is only a cache, so simply drop & recreate the tables + db.execSQL("DROP TABLE IF EXISTS " + RepositoriesColumns.TABLE_NAME); + db.execSQL("DROP TABLE IF EXISTS " + ModulesColumns.TABLE_NAME); + db.execSQL("DROP TABLE IF EXISTS " + ModuleVersionsColumns.TABLE_NAME); + db.execSQL("DROP TABLE IF EXISTS " + MoreInfoColumns.TABLE_NAME); + + db.execSQL( + "DROP TABLE IF EXISTS " + InstalledModulesColumns.TABLE_NAME); + db.execSQL("DROP VIEW IF EXISTS " + + InstalledModulesUpdatesColumns.VIEW_NAME); + + onCreate(db); + } + + @Override + public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + onUpgrade(db, oldVersion, newVersion); + } public static class RowNotFoundException extends RuntimeException { private static final long serialVersionUID = -396324186622439535L; + public RowNotFoundException(String reason) { super(reason); } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDbDefinitions.java b/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDbDefinitions.java index 9ecf99235..c447896ab 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDbDefinitions.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/RepoDbDefinitions.java @@ -6,196 +6,194 @@ public class RepoDbDefinitions { public static final int DATABASE_VERSION = 4; public static final String DATABASE_NAME = "repo_cache.db"; - - -////////////////////////////////////////////////////////////////////////// - public static interface RepositoriesColumns extends BaseColumns { - public static final String TABLE_NAME = "repositories"; - - public static final String URL = "url"; - public static final String TITLE = "title"; - public static final String PARTIAL_URL = "partial_url"; - public static final String VERSION = "version"; + static final String SQL_CREATE_TABLE_REPOSITORIES = "CREATE TABLE " + + RepositoriesColumns.TABLE_NAME + " (" + RepositoriesColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + RepositoriesColumns.URL + + " TEXT NOT NULL, " + RepositoriesColumns.TITLE + " TEXT, " + + RepositoriesColumns.PARTIAL_URL + " TEXT, " + + RepositoriesColumns.VERSION + " TEXT, " + "UNIQUE (" + + RepositoriesColumns.URL + ") ON CONFLICT REPLACE)"; + static final String SQL_CREATE_TABLE_MODULES = "CREATE TABLE " + + ModulesColumns.TABLE_NAME + " (" + ModulesColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + + + ModulesColumns.REPO_ID + " INTEGER NOT NULL REFERENCES " + + RepositoriesColumns.TABLE_NAME + " ON DELETE CASCADE, " + + ModulesColumns.PKGNAME + " TEXT NOT NULL, " + ModulesColumns.TITLE + + " TEXT NOT NULL, " + ModulesColumns.SUMMARY + " TEXT, " + + ModulesColumns.DESCRIPTION + " TEXT, " + + ModulesColumns.DESCRIPTION_IS_HTML + " INTEGER DEFAULT 0, " + + ModulesColumns.AUTHOR + " TEXT, " + ModulesColumns.SUPPORT + + " TEXT, " + ModulesColumns.CREATED + " INTEGER DEFAULT -1, " + + ModulesColumns.UPDATED + " INTEGER DEFAULT -1, " + + ModulesColumns.PREFERRED + " INTEGER DEFAULT 1, " + + ModulesColumns.LATEST_VERSION + " INTEGER REFERENCES " + + ModuleVersionsColumns.TABLE_NAME + ", " + "UNIQUE (" + + ModulesColumns.PKGNAME + ", " + ModulesColumns.REPO_ID + + ") ON CONFLICT REPLACE)"; + static final String SQL_CREATE_TABLE_MODULE_VERSIONS = "CREATE TABLE " + + ModuleVersionsColumns.TABLE_NAME + " (" + + ModuleVersionsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + ModuleVersionsColumns.MODULE_ID + " INTEGER NOT NULL REFERENCES " + + ModulesColumns.TABLE_NAME + " ON DELETE CASCADE, " + + ModuleVersionsColumns.NAME + " TEXT NOT NULL, " + + ModuleVersionsColumns.CODE + " INTEGER NOT NULL, " + + ModuleVersionsColumns.DOWNLOAD_LINK + " TEXT, " + + ModuleVersionsColumns.MD5SUM + " TEXT, " + + ModuleVersionsColumns.CHANGELOG + " TEXT, " + + ModuleVersionsColumns.CHANGELOG_IS_HTML + " INTEGER DEFAULT 0, " + + ModuleVersionsColumns.RELTYPE + " INTEGER DEFAULT 0, " + + ModuleVersionsColumns.UPLOADED + " INTEGER DEFAULT -1)"; + static final String SQL_CREATE_INDEX_MODULE_VERSIONS_MODULE_ID = "CREATE INDEX " + + ModuleVersionsColumns.IDX_MODULE_ID + " ON " + + ModuleVersionsColumns.TABLE_NAME + " (" + + ModuleVersionsColumns.MODULE_ID + ")"; + static final String SQL_CREATE_TABLE_MORE_INFO = "CREATE TABLE " + + MoreInfoColumns.TABLE_NAME + " (" + MoreInfoColumns._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT," + MoreInfoColumns.MODULE_ID + + " INTEGER NOT NULL REFERENCES " + ModulesColumns.TABLE_NAME + + " ON DELETE CASCADE, " + MoreInfoColumns.LABEL + + " TEXT NOT NULL, " + MoreInfoColumns.VALUE + " TEXT)"; + static final String SQL_CREATE_TEMP_TABLE_INSTALLED_MODULES = "CREATE TEMP TABLE " + + InstalledModulesColumns.TABLE_NAME + " (" + + InstalledModulesColumns.PKGNAME + + " TEXT PRIMARY KEY ON CONFLICT REPLACE, " + + InstalledModulesColumns.VERSION_CODE + " INTEGER NOT NULL, " + + InstalledModulesColumns.VERSION_NAME + " TEXT)"; + static final String SQL_CREATE_TEMP_VIEW_INSTALLED_MODULES_UPDATES = "CREATE TEMP VIEW " + + InstalledModulesUpdatesColumns.VIEW_NAME + " AS SELECT " + "m." + + ModulesColumns._ID + " AS " + + InstalledModulesUpdatesColumns.MODULE_ID + ", " + "i." + + InstalledModulesColumns.PKGNAME + " AS " + + InstalledModulesUpdatesColumns.PKGNAME + ", " + "i." + + InstalledModulesColumns.VERSION_CODE + " AS " + + InstalledModulesUpdatesColumns.INSTALLED_CODE + ", " + "i." + + InstalledModulesColumns.VERSION_NAME + " AS " + + InstalledModulesUpdatesColumns.INSTALLED_NAME + ", " + "v." + + ModuleVersionsColumns._ID + " AS " + + InstalledModulesUpdatesColumns.LATEST_ID + ", " + "v." + + ModuleVersionsColumns.CODE + " AS " + + InstalledModulesUpdatesColumns.LATEST_CODE + ", " + "v." + + ModuleVersionsColumns.NAME + " AS " + + InstalledModulesUpdatesColumns.LATEST_NAME + " FROM " + + InstalledModulesColumns.TABLE_NAME + " AS i" + " INNER JOIN " + + ModulesColumns.TABLE_NAME + " AS m" + " ON m." + + ModulesColumns.PKGNAME + " = i." + InstalledModulesColumns.PKGNAME + + " INNER JOIN " + ModuleVersionsColumns.TABLE_NAME + " AS v" + + " ON v." + ModuleVersionsColumns._ID + " = m." + + ModulesColumns.LATEST_VERSION + " WHERE " + + InstalledModulesUpdatesColumns.LATEST_CODE + " > " + + InstalledModulesUpdatesColumns.INSTALLED_CODE + " AND " + + ModulesColumns.PREFERRED + " = 1"; + + ////////////////////////////////////////////////////////////////////////// + public interface RepositoriesColumns extends BaseColumns { + String TABLE_NAME = "repositories"; + + String URL = "url"; + String TITLE = "title"; + String PARTIAL_URL = "partial_url"; + String VERSION = "version"; } - static final String SQL_CREATE_TABLE_REPOSITORIES = - "CREATE TABLE " + RepositoriesColumns.TABLE_NAME + " (" + - RepositoriesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - RepositoriesColumns.URL + " TEXT NOT NULL, " + - RepositoriesColumns.TITLE + " TEXT, " + - RepositoriesColumns.PARTIAL_URL + " TEXT, " + - RepositoriesColumns.VERSION + " TEXT, " + - "UNIQUE (" + RepositoriesColumns.URL + ") ON CONFLICT REPLACE)"; - - -////////////////////////////////////////////////////////////////////////// - public static interface ModulesColumns extends BaseColumns { - public static final String TABLE_NAME = "modules"; - - public static final String REPO_ID = "repo_id"; - public static final String PKGNAME = "pkgname"; - public static final String TITLE = "title"; - public static final String SUMMARY = "summary"; - public static final String DESCRIPTION = "description"; - public static final String DESCRIPTION_IS_HTML = "description_is_html"; - public static final String AUTHOR = "author"; - public static final String SUPPORT = "support"; - public static final String CREATED = "created"; - public static final String UPDATED = "updated"; - - public static final String PREFERRED = "preferred"; - public static final String LATEST_VERSION = "latest_version_id"; + + ////////////////////////////////////////////////////////////////////////// + public interface ModulesColumns extends BaseColumns { + String TABLE_NAME = "modules"; + + String REPO_ID = "repo_id"; + String PKGNAME = "pkgname"; + String TITLE = "title"; + String SUMMARY = "summary"; + String DESCRIPTION = "description"; + String DESCRIPTION_IS_HTML = "description_is_html"; + String AUTHOR = "author"; + String SUPPORT = "support"; + String CREATED = "created"; + String UPDATED = "updated"; + + String PREFERRED = "preferred"; + String LATEST_VERSION = "latest_version_id"; } - static final String SQL_CREATE_TABLE_MODULES = - "CREATE TABLE " + ModulesColumns.TABLE_NAME + " (" + - ModulesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - - ModulesColumns.REPO_ID + " INTEGER NOT NULL REFERENCES " - + RepositoriesColumns.TABLE_NAME + " ON DELETE CASCADE, " + - ModulesColumns.PKGNAME + " TEXT NOT NULL, " + - ModulesColumns.TITLE + " TEXT NOT NULL, " + - ModulesColumns.SUMMARY + " TEXT, " + - ModulesColumns.DESCRIPTION + " TEXT, " + - ModulesColumns.DESCRIPTION_IS_HTML + " INTEGER DEFAULT 0, " + - ModulesColumns.AUTHOR + " TEXT, " + - ModulesColumns.SUPPORT + " TEXT, " + - ModulesColumns.CREATED + " INTEGER DEFAULT -1, " + - ModulesColumns.UPDATED + " INTEGER DEFAULT -1, " + - ModulesColumns.PREFERRED + " INTEGER DEFAULT 1, " + - ModulesColumns.LATEST_VERSION + " INTEGER REFERENCES " + ModuleVersionsColumns.TABLE_NAME + ", " + - "UNIQUE (" + ModulesColumns.PKGNAME + ", " + ModulesColumns.REPO_ID + ") ON CONFLICT REPLACE)"; - - -////////////////////////////////////////////////////////////////////////// - public static interface ModuleVersionsColumns extends BaseColumns { - public static final String TABLE_NAME = "module_versions"; - public static final String IDX_MODULE_ID = "module_versions_module_id_idx"; - - public static final String MODULE_ID = "module_id"; - public static final String NAME = "name"; - public static final String CODE = "code"; - public static final String DOWNLOAD_LINK = "download_link"; - public static final String MD5SUM = "md5sum"; - public static final String CHANGELOG = "changelog"; - public static final String CHANGELOG_IS_HTML = "changelog_is_html"; - public static final String RELTYPE = "reltype"; - public static final String UPLOADED = "uploaded"; + + ////////////////////////////////////////////////////////////////////////// + public interface ModuleVersionsColumns extends BaseColumns { + String TABLE_NAME = "module_versions"; + String IDX_MODULE_ID = "module_versions_module_id_idx"; + + String MODULE_ID = "module_id"; + String NAME = "name"; + String CODE = "code"; + String DOWNLOAD_LINK = "download_link"; + String MD5SUM = "md5sum"; + String CHANGELOG = "changelog"; + String CHANGELOG_IS_HTML = "changelog_is_html"; + String RELTYPE = "reltype"; + String UPLOADED = "uploaded"; } - static final String SQL_CREATE_TABLE_MODULE_VERSIONS = - "CREATE TABLE " + ModuleVersionsColumns.TABLE_NAME + " (" + - ModuleVersionsColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - ModuleVersionsColumns.MODULE_ID + " INTEGER NOT NULL REFERENCES " - + ModulesColumns.TABLE_NAME + " ON DELETE CASCADE, " + - ModuleVersionsColumns.NAME + " TEXT NOT NULL, " + - ModuleVersionsColumns.CODE + " INTEGER NOT NULL, " + - ModuleVersionsColumns.DOWNLOAD_LINK + " TEXT, " + - ModuleVersionsColumns.MD5SUM + " TEXT, " + - ModuleVersionsColumns.CHANGELOG + " TEXT, " + - ModuleVersionsColumns.CHANGELOG_IS_HTML + " INTEGER DEFAULT 0, " + - ModuleVersionsColumns.RELTYPE + " INTEGER DEFAULT 0, " + - ModuleVersionsColumns.UPLOADED + " INTEGER DEFAULT -1)"; - static final String SQL_CREATE_INDEX_MODULE_VERSIONS_MODULE_ID = - "CREATE INDEX " + ModuleVersionsColumns.IDX_MODULE_ID + " ON " + - ModuleVersionsColumns.TABLE_NAME + " (" + - ModuleVersionsColumns.MODULE_ID + ")"; - - -////////////////////////////////////////////////////////////////////////// - public static interface MoreInfoColumns extends BaseColumns { - public static final String TABLE_NAME = "more_info"; - - public static final String MODULE_ID = "module_id"; - public static final String LABEL = "label"; - public static final String VALUE = "value"; + + ////////////////////////////////////////////////////////////////////////// + public interface MoreInfoColumns extends BaseColumns { + String TABLE_NAME = "more_info"; + + String MODULE_ID = "module_id"; + String LABEL = "label"; + String VALUE = "value"; } - static final String SQL_CREATE_TABLE_MORE_INFO = - "CREATE TABLE " + MoreInfoColumns.TABLE_NAME + " (" + - MoreInfoColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - MoreInfoColumns.MODULE_ID + " INTEGER NOT NULL REFERENCES " - + ModulesColumns.TABLE_NAME + " ON DELETE CASCADE, " + - MoreInfoColumns.LABEL + " TEXT NOT NULL, " + - MoreInfoColumns.VALUE + " TEXT)"; - - -////////////////////////////////////////////////////////////////////////// - public static interface InstalledModulesColumns { - public static final String TABLE_NAME = "installed_modules"; - - public static final String PKGNAME = "pkgname"; - public static final String VERSION_CODE = "version_code"; - public static final String VERSION_NAME = "version_name"; + + ////////////////////////////////////////////////////////////////////////// + public interface InstalledModulesColumns { + String TABLE_NAME = "installed_modules"; + + String PKGNAME = "pkgname"; + String VERSION_CODE = "version_code"; + String VERSION_NAME = "version_name"; } - static final String SQL_CREATE_TEMP_TABLE_INSTALLED_MODULES = - "CREATE TEMP TABLE " + InstalledModulesColumns.TABLE_NAME + " (" + - InstalledModulesColumns.PKGNAME + " TEXT PRIMARY KEY ON CONFLICT REPLACE, " + - InstalledModulesColumns.VERSION_CODE + " INTEGER NOT NULL, " + - InstalledModulesColumns.VERSION_NAME + " TEXT)"; - - -////////////////////////////////////////////////////////////////////////// - public static interface InstalledModulesUpdatesColumns { - public static final String VIEW_NAME = InstalledModulesColumns.TABLE_NAME + "_updates"; - - public static final String MODULE_ID = "module_id"; - public static final String PKGNAME = "pkgname"; - public static final String INSTALLED_CODE = "installed_code"; - public static final String INSTALLED_NAME = "installed_name"; - public static final String LATEST_ID = "latest_id"; - public static final String LATEST_CODE = "latest_code"; - public static final String LATEST_NAME = "latest_name"; + + ////////////////////////////////////////////////////////////////////////// + public interface InstalledModulesUpdatesColumns { + String VIEW_NAME = InstalledModulesColumns.TABLE_NAME + "_updates"; + + String MODULE_ID = "module_id"; + String PKGNAME = "pkgname"; + String INSTALLED_CODE = "installed_code"; + String INSTALLED_NAME = "installed_name"; + String LATEST_ID = "latest_id"; + String LATEST_CODE = "latest_code"; + String LATEST_NAME = "latest_name"; } - static final String SQL_CREATE_TEMP_VIEW_INSTALLED_MODULES_UPDATES = - "CREATE TEMP VIEW " + InstalledModulesUpdatesColumns.VIEW_NAME + " AS SELECT " + - "m." + ModulesColumns._ID + " AS " + InstalledModulesUpdatesColumns.MODULE_ID + ", " + - "i." + InstalledModulesColumns.PKGNAME + " AS " + InstalledModulesUpdatesColumns.PKGNAME + ", " + - "i." + InstalledModulesColumns.VERSION_CODE + " AS " + InstalledModulesUpdatesColumns.INSTALLED_CODE + ", " + - "i." + InstalledModulesColumns.VERSION_NAME + " AS " + InstalledModulesUpdatesColumns.INSTALLED_NAME + ", " + - "v." + ModuleVersionsColumns._ID + " AS " + InstalledModulesUpdatesColumns.LATEST_ID + ", " + - "v." + ModuleVersionsColumns.CODE + " AS " + InstalledModulesUpdatesColumns.LATEST_CODE + ", " + - "v." + ModuleVersionsColumns.NAME + " AS " + InstalledModulesUpdatesColumns.LATEST_NAME + - " FROM " + InstalledModulesColumns.TABLE_NAME + " AS i" + - " INNER JOIN " + ModulesColumns.TABLE_NAME + " AS m" + - " ON m." + ModulesColumns.PKGNAME + " = i." + InstalledModulesColumns.PKGNAME + - " INNER JOIN " + ModuleVersionsColumns.TABLE_NAME + " AS v" + - " ON v." + ModuleVersionsColumns._ID + " = m." + ModulesColumns.LATEST_VERSION + - " WHERE " + InstalledModulesUpdatesColumns.LATEST_CODE - + " > " + InstalledModulesUpdatesColumns.INSTALLED_CODE - + " AND " + ModulesColumns.PREFERRED + " = 1"; - - -////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// public interface OverviewColumns extends BaseColumns { - public static final String PKGNAME = ModulesColumns.PKGNAME; - public static final String TITLE = ModulesColumns.TITLE; - public static final String SUMMARY = ModulesColumns.SUMMARY; - public static final String CREATED = ModulesColumns.CREATED; - public static final String UPDATED = ModulesColumns.UPDATED; - - public static final String INSTALLED_VERSION = "installed_version"; - public static final String LATEST_VERSION = "latest_version"; - - public static final String IS_FRAMEWORK = "is_framework"; - public static final String IS_INSTALLED = "is_installed"; - public static final String HAS_UPDATE = "has_update"; + String PKGNAME = ModulesColumns.PKGNAME; + String TITLE = ModulesColumns.TITLE; + String SUMMARY = ModulesColumns.SUMMARY; + String CREATED = ModulesColumns.CREATED; + String UPDATED = ModulesColumns.UPDATED; + + String INSTALLED_VERSION = "installed_version"; + String LATEST_VERSION = "latest_version"; + + String IS_FRAMEWORK = "is_framework"; + String IS_INSTALLED = "is_installed"; + String HAS_UPDATE = "has_update"; } public static class OverviewColumnsIndexes { - private OverviewColumnsIndexes() {} - public static int PKGNAME = -1; public static int TITLE = -1; public static int SUMMARY = -1; public static int CREATED = -1; public static int UPDATED = -1; - public static int INSTALLED_VERSION = -1; public static int LATEST_VERSION = -1; - public static int IS_FRAMEWORK = -1; public static int IS_INSTALLED = -1; public static int HAS_UPDATE = -1; - private static boolean isFilled = false; + private OverviewColumnsIndexes() { + } + public static void fillFromCursor(Cursor cursor) { if (isFilled || cursor == null) return; @@ -205,12 +203,18 @@ public static void fillFromCursor(Cursor cursor) { SUMMARY = cursor.getColumnIndexOrThrow(OverviewColumns.SUMMARY); CREATED = cursor.getColumnIndexOrThrow(OverviewColumns.CREATED); UPDATED = cursor.getColumnIndexOrThrow(OverviewColumns.UPDATED); - INSTALLED_VERSION = cursor.getColumnIndexOrThrow(OverviewColumns.INSTALLED_VERSION); - LATEST_VERSION = cursor.getColumnIndexOrThrow(OverviewColumns.LATEST_VERSION); - INSTALLED_VERSION = cursor.getColumnIndexOrThrow(OverviewColumns.INSTALLED_VERSION); - IS_FRAMEWORK = cursor.getColumnIndexOrThrow(OverviewColumns.IS_FRAMEWORK); - IS_INSTALLED = cursor.getColumnIndexOrThrow(OverviewColumns.IS_INSTALLED); - HAS_UPDATE = cursor.getColumnIndexOrThrow(OverviewColumns.HAS_UPDATE); + INSTALLED_VERSION = cursor + .getColumnIndexOrThrow(OverviewColumns.INSTALLED_VERSION); + LATEST_VERSION = cursor + .getColumnIndexOrThrow(OverviewColumns.LATEST_VERSION); + INSTALLED_VERSION = cursor + .getColumnIndexOrThrow(OverviewColumns.INSTALLED_VERSION); + IS_FRAMEWORK = cursor + .getColumnIndexOrThrow(OverviewColumns.IS_FRAMEWORK); + IS_INSTALLED = cursor + .getColumnIndexOrThrow(OverviewColumns.IS_INSTALLED); + HAS_UPDATE = cursor + .getColumnIndexOrThrow(OverviewColumns.HAS_UPDATE); isFilled = true; } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/RepoParser.java b/app/src/main/java/de/robv/android/xposed/installer/repo/RepoParser.java index 3447faf49..bc3a0d6de 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/RepoParser.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/RepoParser.java @@ -1,5 +1,11 @@ package de.robv.android.xposed.installer.repo; +import android.text.Html; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.util.Log; +import android.util.Pair; + import java.io.IOException; import java.io.InputStream; @@ -7,12 +13,6 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; -import android.text.Html; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.util.Log; -import android.util.Pair; - public class RepoParser { public final static String TAG = "XposedRepoParser"; protected final static String NS = null; @@ -20,18 +20,8 @@ public class RepoParser { protected RepoParserCallback mCallback; private boolean mRepoEventTriggered = false; - public interface RepoParserCallback { - public void onRepositoryMetadata(Repository repository); - public void onNewModule(Module module); - public void onRemoveModule(String packageName); - public void onCompleted(Repository repository); - } - - public static void parse(InputStream is, RepoParserCallback callback) throws XmlPullParserException, IOException { - new RepoParser(is, callback).readRepo(); - } - - protected RepoParser(InputStream is, RepoParserCallback callback) throws XmlPullParserException, IOException { + protected RepoParser(InputStream is, RepoParserCallback callback) + throws XmlPullParserException, IOException { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); parser = factory.newPullParser(); parser.setInput(is, null); @@ -39,10 +29,36 @@ protected RepoParser(InputStream is, RepoParserCallback callback) throws XmlPull mCallback = callback; } + public static void parse(InputStream is, RepoParserCallback callback) + throws XmlPullParserException, IOException { + new RepoParser(is, callback).readRepo(); + } + + public static Spanned parseSimpleHtml(String source) { + source = source.replaceAll("
  • ", "\t\u0095 "); + source = source.replaceAll("
  • ", "
    "); + Spanned html = Html.fromHtml(source); + + // trim trailing newlines + int len = html.length(); + int end = len; + for (int i = len - 1; i >= 0; i--) { + if (html.charAt(i) != '\n') + break; + end = i; + } + + if (end == len) + return html; + else + return new SpannableStringBuilder(html, 0, end); + } + protected void readRepo() throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, NS, "repository"); Repository repository = new Repository(); - repository.isPartial = "true".equals(parser.getAttributeValue(NS, "partial")); + repository.isPartial = "true" + .equals(parser.getAttributeValue(NS, "partial")); repository.partialUrl = parser.getAttributeValue(NS, "partial-url"); repository.version = parser.getAttributeValue(NS, "version"); @@ -76,7 +92,8 @@ private void triggerRepoEvent(Repository repository) { mRepoEventTriggered = true; } - protected Module readModule(Repository repository) throws XmlPullParserException, IOException { + protected Module readModule(Repository repository) + throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, NS, "module"); final int startDepth = parser.getDepth(); @@ -142,27 +159,8 @@ private long parseTimestamp(String attName) { } } - public static Spanned parseSimpleHtml(String source) { - source = source.replaceAll("
  • ", "\t\u0095 "); - source = source.replaceAll("
  • ", "
    "); - Spanned html = Html.fromHtml(source); - - // trim trailing newlines - int len = html.length(); - int end = len; - for (int i = len - 1; i >= 0; i--) { - if (html.charAt(i) != '\n') - break; - end = i; - } - - if (end == len) - return html; - else - return new SpannableStringBuilder(html, 0, end); - } - - protected ModuleVersion readModuleVersion(Module module) throws XmlPullParserException, IOException { + protected ModuleVersion readModuleVersion(Module module) + throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, NS, "version"); final int startDepth = parser.getDepth(); ModuleVersion version = new ModuleVersion(module); @@ -203,7 +201,8 @@ protected ModuleVersion readModuleVersion(Module module) throws XmlPullParserExc return version; } - protected String readRemoveModule() throws XmlPullParserException, IOException { + protected String readRemoveModule() + throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, NS, "remove-module"); final int startDepth = parser.getDepth(); @@ -217,10 +216,12 @@ protected String readRemoveModule() throws XmlPullParserException, IOException { return packageName; } - protected void skip(boolean showWarning) throws XmlPullParserException, IOException { + protected void skip(boolean showWarning) + throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, null, null); if (showWarning) - Log.w(TAG, "skipping unknown/erronous tag: " + parser.getPositionDescription()); + Log.w(TAG, "skipping unknown/erronous tag: " + + parser.getPositionDescription()); int level = 1; while (level > 0) { int eventType = parser.next(); @@ -232,8 +233,10 @@ protected void skip(boolean showWarning) throws XmlPullParserException, IOExcept } } - protected void leave(int targetDepth) throws XmlPullParserException, IOException { - Log.w(TAG, "leaving up to level " + targetDepth + ": " + parser.getPositionDescription()); + protected void leave(int targetDepth) + throws XmlPullParserException, IOException { + Log.w(TAG, "leaving up to level " + targetDepth + ": " + + parser.getPositionDescription()); while (parser.getDepth() > targetDepth) { while (parser.next() != XmlPullParser.END_TAG) { // do nothing @@ -244,4 +247,14 @@ protected void leave(int targetDepth) throws XmlPullParserException, IOException protected void logError(String error) { Log.e(TAG, parser.getPositionDescription() + ": " + error); } + + public interface RepoParserCallback { + void onRepositoryMetadata(Repository repository); + + void onNewModule(Module module); + + void onRemoveModule(String packageName); + + void onCompleted(Repository repository); + } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/repo/Repository.java b/app/src/main/java/de/robv/android/xposed/installer/repo/Repository.java index a223bdd5c..d00b64467 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/repo/Repository.java +++ b/app/src/main/java/de/robv/android/xposed/installer/repo/Repository.java @@ -1,6 +1,5 @@ package de.robv.android.xposed.installer.repo; - public class Repository { public String name; public String url; @@ -8,5 +7,6 @@ public class Repository { public String partialUrl; public String version; - /*package*/ Repository() {}; + /* package */ Repository() { + } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/AssetUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/AssetUtil.java index 640dffbf8..3cfbb35c8 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/AssetUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/AssetUtil.java @@ -1,10 +1,5 @@ package de.robv.android.xposed.installer.util; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -12,10 +7,17 @@ import android.os.Build; import android.os.FileUtils; import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + import de.robv.android.xposed.installer.XposedApp; public class AssetUtil { - public static final File BUSYBOX_FILE = new File(XposedApp.getInstance().getCacheDir(), "busybox-xposed"); + public static final File BUSYBOX_FILE = new File( + XposedApp.getInstance().getCacheDir(), "busybox-xposed"); public static final String STATIC_BUSYBOX_PACKAGE = "de.robv.android.xposed.installer.staticbusybox"; private static final int STATIC_BUSYBOX_REQUIRED_VERSION = 1; private static PackageInfo mStaticBusyboxInfo = null; @@ -34,24 +36,30 @@ public static File writeAssetToCacheFile(String name, int mode) { return writeAssetToCacheFile(name, name, mode); } - public static File writeAssetToCacheFile(String assetName, String fileName, int mode) { - return writeAssetToFile(assetName, new File(XposedApp.getInstance().getCacheDir(), fileName), mode); + public static File writeAssetToCacheFile(String assetName, String fileName, + int mode) { + return writeAssetToFile(assetName, + new File(XposedApp.getInstance().getCacheDir(), fileName), + mode); } public static File writeAssetToSdcardFile(String name, int mode) { return writeAssetToSdcardFile(name, name, mode); } - public static File writeAssetToSdcardFile(String assetName, String fileName, int mode) { + public static File writeAssetToSdcardFile(String assetName, String fileName, + int mode) { File dir = XposedApp.getInstance().getExternalFilesDir(null); return writeAssetToFile(assetName, new File(dir, fileName), mode); } - public static File writeAssetToFile(String assetName, File targetFile, int mode) { + public static File writeAssetToFile(String assetName, File targetFile, + int mode) { return writeAssetToFile(null, assetName, targetFile, mode); } - public static File writeAssetToFile(AssetManager assets, String assetName, File targetFile, int mode) { + public static File writeAssetToFile(AssetManager assets, String assetName, + File targetFile, int mode) { try { if (assets == null) assets = XposedApp.getInstance().getAssets(); @@ -60,13 +68,14 @@ public static File writeAssetToFile(AssetManager assets, String assetName, File byte[] buffer = new byte[1024]; int len; - while ((len = in.read(buffer)) > 0){ + while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); - FileUtils.setPermissions(targetFile.getAbsolutePath(), mode, -1, -1); + FileUtils.setPermissions(targetFile.getAbsolutePath(), mode, -1, + -1); return targetFile; } catch (IOException e) { @@ -86,13 +95,17 @@ public synchronized static void extractBusybox() { if (isStaticBusyboxAvailable()) { try { PackageManager pm = XposedApp.getInstance().getPackageManager(); - assets = pm.getResourcesForApplication(mStaticBusyboxInfo.applicationInfo).getAssets(); + assets = pm.getResourcesForApplication( + mStaticBusyboxInfo.applicationInfo).getAssets(); } catch (NameNotFoundException e) { - Log.e(XposedApp.TAG, "could not load assets from " + STATIC_BUSYBOX_PACKAGE, e); + Log.e(XposedApp.TAG, + "could not load assets from " + STATIC_BUSYBOX_PACKAGE, + e); } } - writeAssetToFile(assets, getBinariesFolder() + "busybox-xposed", BUSYBOX_FILE, 00700); + writeAssetToFile(assets, getBinariesFolder() + "busybox-xposed", + BUSYBOX_FILE, 00700); } public synchronized static void removeBusybox() { @@ -110,15 +123,21 @@ public synchronized static void checkStaticBusyboxAvailability() { return; } - String myPackageName = ModuleUtil.getInstance().getFrameworkPackageName(); - if (pm.checkSignatures(STATIC_BUSYBOX_PACKAGE, myPackageName) != PackageManager.SIGNATURE_MATCH) { - Log.e(XposedApp.TAG, "Rejecting static Busybox package because it is signed with a different key"); + String myPackageName = ModuleUtil.getInstance() + .getFrameworkPackageName(); + if (pm.checkSignatures(STATIC_BUSYBOX_PACKAGE, + myPackageName) != PackageManager.SIGNATURE_MATCH) { + Log.e(XposedApp.TAG, + "Rejecting static Busybox package because it is signed with a different key"); return; } if (mStaticBusyboxInfo.versionCode != STATIC_BUSYBOX_REQUIRED_VERSION) { - Log.e(XposedApp.TAG, String.format("Ignoring static BusyBox package with version %d, we need version %d", - mStaticBusyboxInfo.versionCode, STATIC_BUSYBOX_REQUIRED_VERSION)); + Log.e(XposedApp.TAG, + String.format( + "Ignoring static BusyBox package with version %d, we need version %d", + mStaticBusyboxInfo.versionCode, + STATIC_BUSYBOX_REQUIRED_VERSION)); mStaticBusyboxInfo = null; return; } else if (!wasAvailable) { diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/DownloadsUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/DownloadsUtil.java index ccc421960..85bca9615 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/DownloadsUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/DownloadsUtil.java @@ -1,5 +1,13 @@ package de.robv.android.xposed.installer.util; +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -13,13 +21,6 @@ import java.util.List; import java.util.Map; -import android.app.DownloadManager; -import android.app.DownloadManager.Query; -import android.app.DownloadManager.Request; -import android.content.Context; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.XposedApp; @@ -27,16 +28,19 @@ public class DownloadsUtil { public static final String MIME_TYPE_APK = "application/vnd.android.package-archive"; private static final Map mCallbacks = new HashMap(); private static final XposedApp mApp = XposedApp.getInstance(); - private static final SharedPreferences mPref = mApp.getSharedPreferences("download_cache", Context.MODE_PRIVATE); + private static final SharedPreferences mPref = mApp + .getSharedPreferences("download_cache", Context.MODE_PRIVATE); - public static DownloadInfo add(Context context, String title, String url, DownloadFinishedCallback callback) { + public static DownloadInfo add(Context context, String title, String url, + DownloadFinishedCallback callback) { removeAllForUrl(context, url); synchronized (mCallbacks) { mCallbacks.put(url, callback); } - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) context + .getSystemService(Context.DOWNLOAD_SERVICE); Request request = new Request(Uri.parse(url)); request.setTitle(title); request.setMimeType(MIME_TYPE_APK); @@ -47,7 +51,8 @@ public static DownloadInfo add(Context context, String title, String url, Downlo } public static DownloadInfo getById(Context context, long id) { - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) context + .getSystemService(Context.DOWNLOAD_SERVICE); Cursor c = dm.query(new Query().setFilterById(id)); if (!c.moveToFirst()) return null; @@ -55,30 +60,31 @@ public static DownloadInfo getById(Context context, long id) { int columnId = c.getColumnIndexOrThrow(DownloadManager.COLUMN_ID); int columnUri = c.getColumnIndexOrThrow(DownloadManager.COLUMN_URI); int columnTitle = c.getColumnIndexOrThrow(DownloadManager.COLUMN_TITLE); - int columnLastMod = c.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); - int columnFilename = c.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME); - int columnStatus = c.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS); - int columnTotalSize = c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES); - int columnBytesDownloaded = c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); - int columnReason = c.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON); + int columnLastMod = c.getColumnIndexOrThrow( + DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); + int columnFilename = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME); + int columnStatus = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS); + int columnTotalSize = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES); + int columnBytesDownloaded = c.getColumnIndexOrThrow( + DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); + int columnReason = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_REASON); String localFilename = c.getString(columnFilename); - if (localFilename != null && !localFilename.isEmpty() && !new File(localFilename).isFile()) { + if (localFilename != null && !localFilename.isEmpty() + && !new File(localFilename).isFile()) { dm.remove(c.getLong(columnId)); return null; } - return new DownloadInfo( - c.getLong(columnId), - c.getString(columnUri), - c.getString(columnTitle), - c.getLong(columnLastMod), - localFilename, - c.getInt(columnStatus), - c.getInt(columnTotalSize), - c.getInt(columnBytesDownloaded), - c.getInt(columnReason) - ); + return new DownloadInfo(c.getLong(columnId), c.getString(columnUri), + c.getString(columnTitle), c.getLong(columnLastMod), + localFilename, c.getInt(columnStatus), + c.getInt(columnTotalSize), c.getInt(columnBytesDownloaded), + c.getInt(columnReason)); } public static DownloadInfo getLatestForUrl(Context context, String url) { @@ -87,17 +93,24 @@ public static DownloadInfo getLatestForUrl(Context context, String url) { } public static List getAllForUrl(Context context, String url) { - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) context + .getSystemService(Context.DOWNLOAD_SERVICE); Cursor c = dm.query(new Query()); int columnId = c.getColumnIndexOrThrow(DownloadManager.COLUMN_ID); int columnUri = c.getColumnIndexOrThrow(DownloadManager.COLUMN_URI); int columnTitle = c.getColumnIndexOrThrow(DownloadManager.COLUMN_TITLE); - int columnLastMod = c.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); - int columnFilename = c.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME); - int columnStatus = c.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS); - int columnTotalSize = c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES); - int columnBytesDownloaded = c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); - int columnReason = c.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON); + int columnLastMod = c.getColumnIndexOrThrow( + DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); + int columnFilename = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_FILENAME); + int columnStatus = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS); + int columnTotalSize = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES); + int columnBytesDownloaded = c.getColumnIndexOrThrow( + DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); + int columnReason = c + .getColumnIndexOrThrow(DownloadManager.COLUMN_REASON); List downloads = new ArrayList(); while (c.moveToNext()) { @@ -105,22 +118,17 @@ public static List getAllForUrl(Context context, String url) { continue; String localFilename = c.getString(columnFilename); - if (localFilename != null && !localFilename.isEmpty() && !new File(localFilename).isFile()) { + if (localFilename != null && !localFilename.isEmpty() + && !new File(localFilename).isFile()) { dm.remove(c.getLong(columnId)); continue; } - downloads.add(new DownloadInfo( - c.getLong(columnId), - c.getString(columnUri), - c.getString(columnTitle), - c.getLong(columnLastMod), - localFilename, - c.getInt(columnStatus), - c.getInt(columnTotalSize), - c.getInt(columnBytesDownloaded), - c.getInt(columnReason) - )); + downloads.add(new DownloadInfo(c.getLong(columnId), + c.getString(columnUri), c.getString(columnTitle), + c.getLong(columnLastMod), localFilename, + c.getInt(columnStatus), c.getInt(columnTotalSize), + c.getInt(columnBytesDownloaded), c.getInt(columnReason))); } Collections.sort(downloads); @@ -128,12 +136,14 @@ public static List getAllForUrl(Context context, String url) { } public static void removeById(Context context, long id) { - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) context + .getSystemService(Context.DOWNLOAD_SERVICE); dm.remove(id); } public static void removeAllForUrl(Context context, String url) { - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) context + .getSystemService(Context.DOWNLOAD_SERVICE); Cursor c = dm.query(new Query()); int columnId = c.getColumnIndexOrThrow(DownloadManager.COLUMN_ID); int columnUri = c.getColumnIndexOrThrow(DownloadManager.COLUMN_URI); @@ -154,12 +164,13 @@ public static void removeAllForUrl(Context context, String url) { dm.remove(ids); } - public static void removeOutdated(Context context, long cutoff) { - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager dm = (DownloadManager) context + .getSystemService(Context.DOWNLOAD_SERVICE); Cursor c = dm.query(new Query()); int columnId = c.getColumnIndexOrThrow(DownloadManager.COLUMN_ID); - int columnLastMod = c.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); + int columnLastMod = c.getColumnIndexOrThrow( + DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); List idsList = new ArrayList(); while (c.moveToNext()) { @@ -177,8 +188,8 @@ public static void removeOutdated(Context context, long cutoff) { dm.remove(ids); } - - public static void triggerDownloadFinishedCallback(Context context, long id) { + public static void triggerDownloadFinishedCallback(Context context, + long id) { DownloadInfo info = getById(context, id); if (info == null || info.status != DownloadManager.STATUS_SUCCESSFUL) return; @@ -194,46 +205,8 @@ public static void triggerDownloadFinishedCallback(Context context, long id) { callback.onDownloadFinished(context, info); } - - public static class DownloadInfo implements Comparable { - public final long id; - public final String url; - public final String title; - public final long lastModification; - public final String localFilename; - public final int status; - public final int totalSize; - public final int bytesDownloaded; - public final int reason; - - private DownloadInfo(long id, String url, String title, long lastModification, String localFilename, - int status, int totalSize, int bytesDownloaded, int reason) { - this.id = id; - this.url = url; - this.title = title; - this.lastModification = lastModification; - this.localFilename = localFilename; - this.status = status; - this.totalSize = totalSize; - this.bytesDownloaded = bytesDownloaded; - this.reason = reason; - } - - @Override - public int compareTo(DownloadInfo another) { - int compare = (int)(another.lastModification - this.lastModification); - if (compare != 0) - return compare; - return this.url.compareTo(another.url); - } - } - - public static interface DownloadFinishedCallback { - public void onDownloadFinished(Context context, DownloadInfo info); - } - - - public static SyncDownloadInfo downloadSynchronously(String url, File target) { + public static SyncDownloadInfo downloadSynchronously(String url, + File target) { // TODO Potential parameter? final boolean useNotModifiedTags = true; @@ -249,14 +222,18 @@ public static SyncDownloadInfo downloadSynchronously(String url, File target) { if (connection instanceof HttpURLConnection) { // Disable transparent gzip encoding for gzipped files if (url.endsWith(".gz")) - connection.addRequestProperty("Accept-Encoding", "identity"); + connection.addRequestProperty("Accept-Encoding", + "identity"); if (useNotModifiedTags) { - String modified = mPref.getString("download_" + url + "_modified", null); - String etag = mPref.getString("download_" + url + "_etag", null); + String modified = mPref + .getString("download_" + url + "_modified", null); + String etag = mPref.getString("download_" + url + "_etag", + null); if (modified != null) - connection.addRequestProperty("If-Modified-Since", modified); + connection.addRequestProperty("If-Modified-Since", + modified); if (etag != null) connection.addRequestProperty("If-None-Match", etag); } @@ -268,11 +245,13 @@ public static SyncDownloadInfo downloadSynchronously(String url, File target) { HttpURLConnection httpConnection = (HttpURLConnection) connection; int responseCode = httpConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) { - return new SyncDownloadInfo(SyncDownloadInfo.STATUS_NOT_MODIFIED, null); + return new SyncDownloadInfo( + SyncDownloadInfo.STATUS_NOT_MODIFIED, null); } else if (responseCode < 200 || responseCode >= 300) { return new SyncDownloadInfo(SyncDownloadInfo.STATUS_FAILED, - mApp.getString(R.string.repo_download_failed_http, url, responseCode, - httpConnection.getResponseMessage())); + mApp.getString(R.string.repo_download_failed_http, + url, responseCode, + httpConnection.getResponseMessage())); } } @@ -286,42 +265,85 @@ public static SyncDownloadInfo downloadSynchronously(String url, File target) { if (useNotModifiedTags && connection instanceof HttpURLConnection) { HttpURLConnection httpConnection = (HttpURLConnection) connection; - String modified = httpConnection.getHeaderField("Last-Modified"); + String modified = httpConnection + .getHeaderField("Last-Modified"); String etag = httpConnection.getHeaderField("ETag"); mPref.edit() - .putString("download_" + url + "_modified", modified) - .putString("download_" + url + "_etag", etag) - .commit(); + .putString("download_" + url + "_modified", modified) + .putString("download_" + url + "_etag", etag).commit(); } return new SyncDownloadInfo(SyncDownloadInfo.STATUS_SUCCESS, null); } catch (Throwable t) { return new SyncDownloadInfo(SyncDownloadInfo.STATUS_FAILED, - mApp.getString(R.string.repo_download_failed, url, t.getMessage())); + mApp.getString(R.string.repo_download_failed, url, + t.getMessage())); } finally { if (connection != null && connection instanceof HttpURLConnection) ((HttpURLConnection) connection).disconnect(); if (in != null) - try { in.close(); } catch (IOException ignored) {} + try { + in.close(); + } catch (IOException ignored) { + } if (out != null) - try { out.close(); } catch (IOException ignored) {} + try { + out.close(); + } catch (IOException ignored) { + } } } public static void clearCache(String url) { if (url != null) { - mPref.edit() - .remove("download_" + url + "_modified") - .remove("download_" + url + "_etag") - .apply(); + mPref.edit().remove("download_" + url + "_modified") + .remove("download_" + url + "_etag").apply(); } else { mPref.edit().clear().apply(); } } + public interface DownloadFinishedCallback { + void onDownloadFinished(Context context, DownloadInfo info); + } + + public static class DownloadInfo implements Comparable { + public final long id; + public final String url; + public final String title; + public final long lastModification; + public final String localFilename; + public final int status; + public final int totalSize; + public final int bytesDownloaded; + public final int reason; + + private DownloadInfo(long id, String url, String title, + long lastModification, String localFilename, int status, + int totalSize, int bytesDownloaded, int reason) { + this.id = id; + this.url = url; + this.title = title; + this.lastModification = lastModification; + this.localFilename = localFilename; + this.status = status; + this.totalSize = totalSize; + this.bytesDownloaded = bytesDownloaded; + this.reason = reason; + } + + @Override + public int compareTo(DownloadInfo another) { + int compare = (int) (another.lastModification + - this.lastModification); + if (compare != 0) + return compare; + return this.url.compareTo(another.url); + } + } public static class SyncDownloadInfo { public static final int STATUS_SUCCESS = 0; @@ -337,4 +359,3 @@ private SyncDownloadInfo(int status, String errorMessage) { } } } - diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/HashUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/HashUtil.java index 5daaf5413..b7e626006 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/HashUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/HashUtil.java @@ -26,8 +26,8 @@ public static final String sha1(String input) { return hash(input, "SHA-1"); } - - public static final String hash(File file, String algorithm) throws IOException { + public static final String hash(File file, String algorithm) + throws IOException { try { MessageDigest md = MessageDigest.getInstance(algorithm); InputStream is = new FileInputStream(file); @@ -52,7 +52,6 @@ public static final String sha1(File input) throws IOException { return hash(input, "SHA-1"); } - private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/ModuleUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/ModuleUtil.java index 6f47960b1..8c5a94291 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/ModuleUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/ModuleUtil.java @@ -1,13 +1,5 @@ package de.robv.android.xposed.installer.util; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; - import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; @@ -18,29 +10,39 @@ import android.os.FileUtils; import android.util.Log; import android.widget.Toast; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.XposedApp; import de.robv.android.xposed.installer.repo.ModuleVersion; import de.robv.android.xposed.installer.repo.RepoDb; - public final class ModuleUtil { + // xposedminversion below this + private static final String MODULES_LIST_FILE = XposedApp.BASE_DIR + + "conf/modules.list"; + public static int MIN_MODULE_VERSION = 2; // reject modules with private static ModuleUtil mInstance = null; private final XposedApp mApp; - private SharedPreferences mPref; private final PackageManager mPm; private final String mFrameworkPackageName; + private final List mListeners = new CopyOnWriteArrayList(); + private SharedPreferences mPref; private InstalledModule mFramework = null; private Map mInstalledModules; private boolean mIsReloading = false; - private final List mListeners = new CopyOnWriteArrayList(); - - public static int MIN_MODULE_VERSION = 2; // reject modules with xposedminversion below this - private static final String MODULES_LIST_FILE = XposedApp.BASE_DIR + "conf/modules.list"; private ModuleUtil() { mApp = XposedApp.getInstance(); - mPref = mApp.getSharedPreferences("enabled_modules", Context.MODE_PRIVATE); + mPref = mApp.getSharedPreferences("enabled_modules", + Context.MODE_PRIVATE); mPm = mApp.getPackageManager(); mFrameworkPackageName = mApp.getPackageName(); } @@ -53,6 +55,18 @@ public static synchronized ModuleUtil getInstance() { return mInstance; } + public static int extractIntPart(String str) { + int result = 0, length = str.length(); + for (int offset = 0; offset < length; offset++) { + char c = str.charAt(offset); + if ('0' <= c && c <= '9') + result = result * 10 + (c - '0'); + else + break; + } + return result; + } + public void reloadInstalledModules() { synchronized (this) { if (mIsReloading) @@ -66,13 +80,15 @@ public void reloadInstalledModules() { try { RepoDb.deleteAllInstalledModules(); - for (PackageInfo pkg : mPm.getInstalledPackages(PackageManager.GET_META_DATA)) { + for (PackageInfo pkg : mPm + .getInstalledPackages(PackageManager.GET_META_DATA)) { ApplicationInfo app = pkg.applicationInfo; if (!app.enabled) continue; InstalledModule installed = null; - if (app.metaData != null && app.metaData.containsKey("xposedmodule")) { + if (app.metaData != null + && app.metaData.containsKey("xposedmodule")) { installed = new InstalledModule(pkg, false); modules.put(pkg.packageName, installed); } else if (isFramework(pkg.packageName)) { @@ -107,19 +123,22 @@ public InstalledModule reloadSingleModule(String packageName) { InstalledModule old = mInstalledModules.remove(packageName); if (old != null) { for (ModuleListener listener : mListeners) { - listener.onSingleInstalledModuleReloaded(mInstance, packageName, null); + listener.onSingleInstalledModuleReloaded(mInstance, + packageName, null); } } return null; } ApplicationInfo app = pkg.applicationInfo; - if (app.enabled && app.metaData != null && app.metaData.containsKey("xposedmodule")) { + if (app.enabled && app.metaData != null + && app.metaData.containsKey("xposedmodule")) { InstalledModule module = new InstalledModule(pkg, false); RepoDb.insertInstalledModule(module); mInstalledModules.put(packageName, module); for (ModuleListener listener : mListeners) { - listener.onSingleInstalledModuleReloaded(mInstance, packageName, module); + listener.onSingleInstalledModuleReloaded(mInstance, packageName, + module); } return module; } else { @@ -127,7 +146,8 @@ public InstalledModule reloadSingleModule(String packageName) { InstalledModule old = mInstalledModules.remove(packageName); if (old != null) { for (ModuleListener listener : mListeners) { - listener.onSingleInstalledModuleReloaded(mInstance, packageName, null); + listener.onSingleInstalledModuleReloaded(mInstance, + packageName, null); } } return null; @@ -151,7 +171,8 @@ public boolean isFramework(String packageName) { } public boolean isInstalled(String packageName) { - return mInstalledModules.containsKey(packageName) || isFramework(packageName); + return mInstalledModules.containsKey(packageName) + || isFramework(packageName); } public InstalledModule getModule(String packageName) { @@ -192,14 +213,16 @@ public synchronized void updateModulesList(boolean showToast) { Log.i(XposedApp.TAG, "updating modules.list"); int installedXposedVersion = XposedApp.getActiveXposedVersion(); if (installedXposedVersion <= 0) { - Toast.makeText(mApp, "The Xposed framework is not installed", Toast.LENGTH_SHORT).show(); + Toast.makeText(mApp, "The Xposed framework is not installed", + Toast.LENGTH_SHORT).show(); return; } PrintWriter modulesList = new PrintWriter(MODULES_LIST_FILE); List enabledModules = getEnabledModules(); for (InstalledModule module : enabledModules) { - if (module.minVersion > installedXposedVersion || module.minVersion < MIN_MODULE_VERSION) + if (module.minVersion > installedXposedVersion + || module.minVersion < MIN_MODULE_VERSION) continue; modulesList.println(module.app.sourceDir); @@ -209,35 +232,45 @@ public synchronized void updateModulesList(boolean showToast) { FileUtils.setPermissions(MODULES_LIST_FILE, 00664, -1, -1); if (showToast) - Toast.makeText(mApp, R.string.xposed_module_list_updated, Toast.LENGTH_SHORT).show(); + Toast.makeText(mApp, R.string.xposed_module_list_updated, + Toast.LENGTH_SHORT).show(); } catch (IOException e) { Log.e(XposedApp.TAG, "cannot write " + MODULES_LIST_FILE, e); - Toast.makeText(mApp, "cannot write " + MODULES_LIST_FILE, Toast.LENGTH_SHORT).show(); + Toast.makeText(mApp, "cannot write " + MODULES_LIST_FILE, + Toast.LENGTH_SHORT).show(); } } - public static int extractIntPart(String str) { - int result = 0, length = str.length(); - for (int offset = 0; offset < length; offset++) { - char c = str.charAt(offset); - if ('0' <= c && c <= '9') - result = result * 10 + (c - '0'); - else - break; - } - return result; + public void addListener(ModuleListener listener) { + if (!mListeners.contains(listener)) + mListeners.add(listener); } + public void removeListener(ModuleListener listener) { + mListeners.remove(listener); + } + public interface ModuleListener { + /** + * Called whenever one (previously or now) installed module has been + * reloaded + */ + void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, + String packageName, InstalledModule module); + + /** + * Called whenever all installed modules have been reloaded + */ + void onInstalledModulesReloaded(ModuleUtil moduleUtil); + } public class InstalledModule { - public ApplicationInfo app; public final String packageName; public final boolean isFramework; public final String versionName; public final int versionCode; public final int minVersion; - + public ApplicationInfo app; private String appName; // loaded lazyily private String description; // loaded lazyily @@ -281,10 +314,13 @@ public String getDescription() { try { int resId = (Integer) descriptionRaw; if (resId != 0) - descriptionTmp = mPm.getResourcesForApplication(app).getString(resId).trim(); - } catch (Exception ignored) {} + descriptionTmp = mPm.getResourcesForApplication(app) + .getString(resId).trim(); + } catch (Exception ignored) { + } } - this.description = (descriptionTmp != null) ? descriptionTmp : ""; + this.description = (descriptionTmp != null) ? descriptionTmp + : ""; } return this.description; } @@ -307,27 +343,4 @@ public String toString() { return getAppName(); } } - - - - public void addListener(ModuleListener listener) { - if (!mListeners.contains(listener)) - mListeners.add(listener); - } - - public void removeListener(ModuleListener listener) { - mListeners.remove(listener); - } - - public interface ModuleListener { - /** - * Called whenever one (previously or now) installed module has been reloaded - */ - public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, InstalledModule module); - - /** - * Called whenever all installed modules have been reloaded - */ - public void onInstalledModulesReloaded(ModuleUtil moduleUtil); - } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/NavUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/NavUtil.java index 6b15a0b49..5cffaa03e 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/NavUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/NavUtil.java @@ -10,22 +10,26 @@ import android.text.SpannableString; import android.text.style.URLSpan; import android.text.util.Linkify; + import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.XposedBaseActivity; public final class NavUtil { public static final String FINISH_ON_UP_NAVIGATION = "finish_on_up_navigation"; - public static final Uri EXAMPLE_URI = Uri.fromParts("http", "//example.org", null); + public static final Uri EXAMPLE_URI = Uri.fromParts("http", "//example.org", + null); public static void setTransitionSlideEnter(Activity activity) { - activity.overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left); + activity.overridePendingTransition(R.anim.slide_in_right, + R.anim.slide_out_left); if (activity instanceof XposedBaseActivity) ((XposedBaseActivity) activity).setLeftWithSlideAnim(true); } public static void setTransitionSlideLeave(Activity activity) { - activity.overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right); + activity.overridePendingTransition(R.anim.slide_in_left, + R.anim.slide_out_right); } public static Uri parseURL(String str) { @@ -34,7 +38,8 @@ public static Uri parseURL(String str) { Spannable spannable = new SpannableString(str); Linkify.addLinks(spannable, Linkify.ALL); - URLSpan spans[] = spannable.getSpans(0, spannable.length(), URLSpan.class); + URLSpan spans[] = spannable.getSpans(0, spannable.length(), + URLSpan.class); return (spans.length > 0) ? Uri.parse(spans[0].getURL()) : null; } @@ -42,9 +47,11 @@ public static void startURL(Context context, Uri uri) { Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); - if ("http".equals(uri.getScheme()) && "repo.xposed.info".equals(uri.getHost())) { + if ("http".equals(uri.getScheme()) + && "repo.xposed.info".equals(uri.getHost())) { Intent browser = new Intent(Intent.ACTION_VIEW, EXAMPLE_URI); - ComponentName browserApp = browser.resolveActivity(context.getPackageManager()); + ComponentName browserApp = browser + .resolveActivity(context.getPackageManager()); intent.setComponent(browserApp); } diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/NotificationUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/NotificationUtil.java index 6e8ee408a..5e414609f 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/NotificationUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/NotificationUtil.java @@ -1,8 +1,5 @@ package de.robv.android.xposed.installer.util; -import java.util.LinkedList; -import java.util.List; - import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -12,29 +9,33 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; + +import java.util.LinkedList; +import java.util.List; + import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.XposedApp; import de.robv.android.xposed.installer.XposedBaseActivity; public final class NotificationUtil { - private static Context sContext = null; - private static NotificationManager sNotificationManager; - public static final int NOTIFICATION_MODULE_NOT_ACTIVATED_YET = 0; public static final int NOTIFICATION_MODULES_UPDATED = 1; - private static final int PENDING_INTENT_OPEN_MODULES = 0; private static final int PENDING_INTENT_OPEN_INSTALL = 1; private static final int PENDING_INTENT_SOFT_REBOOT = 2; private static final int PENDING_INTENT_REBOOT = 3; private static final int PENDING_INTENT_ACTIVATE_MODULE_AND_REBOOT = 4; + private static Context sContext = null; + private static NotificationManager sNotificationManager; public static void init() { if (sContext != null) - throw new IllegalStateException("NotificationUtil has already been initialized"); + throw new IllegalStateException( + "NotificationUtil has already been initialized"); sContext = XposedApp.getInstance(); - sNotificationManager = (NotificationManager) sContext.getSystemService(Context.NOTIFICATION_SERVICE); + sNotificationManager = (NotificationManager) sContext + .getSystemService(Context.NOTIFICATION_SERVICE); } public static void cancel(int id) { @@ -45,75 +46,90 @@ public static void cancelAll() { sNotificationManager.cancelAll(); } - public static void showNotActivatedNotification(String packageName, String appName) { + public static void showNotActivatedNotification(String packageName, + String appName) { Intent iModulesTab = new Intent(sContext, XposedBaseActivity.class); - //iModulesTab.putExtra(XposedInstallerActivity.EXTRA_SECTION, XposedInstallerActivity.TAB_MODULES); + // iModulesTab.putExtra(XposedInstallerActivity.EXTRA_SECTION, + // XposedInstallerActivity.TAB_MODULES); iModulesTab.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pModulesTab = PendingIntent.getActivity(sContext, PENDING_INTENT_OPEN_MODULES, - iModulesTab, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pModulesTab = PendingIntent.getActivity(sContext, + PENDING_INTENT_OPEN_MODULES, iModulesTab, + PendingIntent.FLAG_UPDATE_CURRENT); String title = sContext.getString(R.string.module_is_not_activated_yet); - NotificationCompat.Builder builder = new NotificationCompat.Builder(sContext) - .setContentTitle(title) - .setContentText(appName) - .setTicker(title) - .setContentIntent(pModulesTab) - .setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification); + NotificationCompat.Builder builder = new NotificationCompat.Builder( + sContext).setContentTitle(title).setContentText(appName) + .setTicker(title).setContentIntent(pModulesTab) + .setAutoCancel(true) + .setSmallIcon(R.drawable.ic_notification); if (Build.VERSION.SDK_INT >= 16) { - Intent iActivateAndReboot = new Intent(sContext, RebootReceiver.class); - iActivateAndReboot.putExtra(RebootReceiver.EXTRA_ACTIVATE_MODULE, packageName); - PendingIntent pActivateAndReboot = PendingIntent.getBroadcast(sContext, PENDING_INTENT_ACTIVATE_MODULE_AND_REBOOT, + Intent iActivateAndReboot = new Intent(sContext, + RebootReceiver.class); + iActivateAndReboot.putExtra(RebootReceiver.EXTRA_ACTIVATE_MODULE, + packageName); + PendingIntent pActivateAndReboot = PendingIntent.getBroadcast( + sContext, PENDING_INTENT_ACTIVATE_MODULE_AND_REBOOT, iActivateAndReboot, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.BigTextStyle notiStyle = new NotificationCompat.BigTextStyle(); notiStyle.setBigContentTitle(title); - notiStyle.bigText(sContext.getString(R.string.module_is_not_activated_yet_detailed, appName)); + notiStyle.bigText(sContext.getString( + R.string.module_is_not_activated_yet_detailed, appName)); builder.setStyle(notiStyle); - // Only show the quick activation button if any module has been enabled before, + // Only show the quick activation button if any module has been + // enabled before, // to ensure that the user know the way to disable the module later. if (!ModuleUtil.getInstance().getEnabledModules().isEmpty()) - builder.addAction(R.drawable.ic_menu_refresh, sContext.getString(R.string.activate_and_reboot), pActivateAndReboot); + builder.addAction(R.drawable.ic_menu_refresh, + sContext.getString(R.string.activate_and_reboot), + pActivateAndReboot); } - sNotificationManager.notify(packageName, NOTIFICATION_MODULE_NOT_ACTIVATED_YET, builder.build()); + sNotificationManager.notify(packageName, + NOTIFICATION_MODULE_NOT_ACTIVATED_YET, builder.build()); } public static void showModulesUpdatedNotification() { Intent iInstallTab = new Intent(sContext, XposedBaseActivity.class); - //iInstallTab.putExtra(XposedInstallerActivity.EXTRA_SECTION, XposedInstallerActivity.TAB_INSTALL); + // iInstallTab.putExtra(XposedInstallerActivity.EXTRA_SECTION, + // XposedInstallerActivity.TAB_INSTALL); iInstallTab.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pInstallTab = PendingIntent.getActivity(sContext, PENDING_INTENT_OPEN_INSTALL, - iInstallTab, PendingIntent.FLAG_UPDATE_CURRENT); - - String title = sContext.getString(R.string.xposed_module_updated_notification_title); - String message = sContext.getString(R.string.xposed_module_updated_notification); - NotificationCompat.Builder builder = new NotificationCompat.Builder(sContext) - .setContentTitle(title) - .setContentText(message) - .setTicker(title) - .setContentIntent(pInstallTab) - .setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification); + PendingIntent pInstallTab = PendingIntent.getActivity(sContext, + PENDING_INTENT_OPEN_INSTALL, iInstallTab, + PendingIntent.FLAG_UPDATE_CURRENT); + + String title = sContext + .getString(R.string.xposed_module_updated_notification_title); + String message = sContext + .getString(R.string.xposed_module_updated_notification); + NotificationCompat.Builder builder = new NotificationCompat.Builder( + sContext).setContentTitle(title).setContentText(message) + .setTicker(title).setContentIntent(pInstallTab) + .setAutoCancel(true) + .setSmallIcon(R.drawable.ic_notification); if (Build.VERSION.SDK_INT >= 16) { Intent iSoftReboot = new Intent(sContext, RebootReceiver.class); iSoftReboot.putExtra(RebootReceiver.EXTRA_SOFT_REBOOT, true); - PendingIntent pSoftReboot = PendingIntent.getBroadcast(sContext, PENDING_INTENT_SOFT_REBOOT, - iSoftReboot, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pSoftReboot = PendingIntent.getBroadcast(sContext, + PENDING_INTENT_SOFT_REBOOT, iSoftReboot, + PendingIntent.FLAG_UPDATE_CURRENT); Intent iReboot = new Intent(sContext, RebootReceiver.class); - PendingIntent pReboot = PendingIntent.getBroadcast(sContext, PENDING_INTENT_REBOOT, - iReboot, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pReboot = PendingIntent.getBroadcast(sContext, + PENDING_INTENT_REBOOT, iReboot, + PendingIntent.FLAG_UPDATE_CURRENT); builder.addAction(0, sContext.getString(R.string.reboot), pReboot); - builder.addAction(0, sContext.getString(R.string.soft_reboot), pSoftReboot); + builder.addAction(0, sContext.getString(R.string.soft_reboot), + pSoftReboot); } - sNotificationManager.notify(null, NOTIFICATION_MODULES_UPDATED, builder.build()); + sNotificationManager.notify(null, NOTIFICATION_MODULES_UPDATED, + builder.build()); } public static class RebootReceiver extends BroadcastReceiver { @@ -123,21 +139,24 @@ public static class RebootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { /* - * Close the notification bar in order to see the toast - * that module was enabled successfully. - * Furthermore, if SU permissions haven't been granted yet, - * the SU dialog will be prompted behind the expanded notification - * panel and is therefore not visible to the user. + * Close the notification bar in order to see the toast that module + * was enabled successfully. Furthermore, if SU permissions haven't + * been granted yet, the SU dialog will be prompted behind the + * expanded notification panel and is therefore not visible to the + * user. */ - sContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + sContext.sendBroadcast( + new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); cancelAll(); if (intent.hasExtra(EXTRA_ACTIVATE_MODULE)) { - String packageName = intent.getStringExtra(EXTRA_ACTIVATE_MODULE); + String packageName = intent + .getStringExtra(EXTRA_ACTIVATE_MODULE); ModuleUtil moduleUtil = ModuleUtil.getInstance(); moduleUtil.setModuleEnabled(packageName, true); moduleUtil.updateModulesList(false); - Toast.makeText(sContext, R.string.module_activated, Toast.LENGTH_SHORT).show(); + Toast.makeText(sContext, R.string.module_activated, + Toast.LENGTH_SHORT).show(); } RootUtil rootUtil = new RootUtil(); @@ -147,10 +166,13 @@ public void onReceive(Context context, Intent intent) { } List messages = new LinkedList(); - boolean isSoftReboot = intent.getBooleanExtra(EXTRA_SOFT_REBOOT, false); - int returnCode = isSoftReboot ? - rootUtil.execute("setprop ctl.restart surfaceflinger; setprop ctl.restart zygote", messages) - : rootUtil.executeWithBusybox("reboot", messages); + boolean isSoftReboot = intent.getBooleanExtra(EXTRA_SOFT_REBOOT, + false); + int returnCode = isSoftReboot + ? rootUtil.execute( + "setprop ctl.restart surfaceflinger; setprop ctl.restart zygote", + messages) + : rootUtil.executeWithBusybox("reboot", messages); if (returnCode != 0) { Log.e(XposedApp.TAG, "Could not reboot:"); diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/PrefixedSharedPreferences.java b/app/src/main/java/de/robv/android/xposed/installer/util/PrefixedSharedPreferences.java index 990adf25d..98e81657a 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/PrefixedSharedPreferences.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/PrefixedSharedPreferences.java @@ -1,15 +1,15 @@ package de.robv.android.xposed.installer.util; +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import android.annotation.SuppressLint; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - public class PrefixedSharedPreferences implements SharedPreferences { private final SharedPreferences mBase; private final String mPrefix; @@ -19,11 +19,14 @@ public PrefixedSharedPreferences(SharedPreferences base, String prefix) { mPrefix = prefix + "_"; } - public static void injectToPreferenceManager(PreferenceManager manager, String prefix) { - SharedPreferences prefixedPrefs = new PrefixedSharedPreferences(manager.getSharedPreferences(), prefix); + public static void injectToPreferenceManager(PreferenceManager manager, + String prefix) { + SharedPreferences prefixedPrefs = new PrefixedSharedPreferences( + manager.getSharedPreferences(), prefix); try { - Field fieldSharedPref = PreferenceManager.class.getDeclaredField("mSharedPreferences"); + Field fieldSharedPref = PreferenceManager.class + .getDeclaredField("mSharedPreferences"); fieldSharedPref.setAccessible(true); fieldSharedPref.set(manager, prefixedPrefs); } catch (Throwable t) { @@ -34,7 +37,8 @@ public static void injectToPreferenceManager(PreferenceManager manager, String p @Override public Map getAll() { Map baseResult = mBase.getAll(); - Map prefixedResult = new HashMap(baseResult); + Map prefixedResult = new HashMap( + baseResult); for (Entry entry : baseResult.entrySet()) { prefixedResult.put(mPrefix + entry.getKey(), entry.getValue()); } @@ -83,16 +87,19 @@ public Editor edit() { } @Override - public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { - throw new UnsupportedOperationException("listeners are not supported in this implementation"); + public void registerOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) { + throw new UnsupportedOperationException( + "listeners are not supported in this implementation"); } @Override - public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { - throw new UnsupportedOperationException("listeners are not supported in this implementation"); + public void unregisterOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) { + throw new UnsupportedOperationException( + "listeners are not supported in this implementation"); } - private class EditorImpl implements Editor { private final Editor mEditorBase; diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/RepoLoader.java b/app/src/main/java/de/robv/android/xposed/installer/util/RepoLoader.java index 7b7111be4..cd16f33e6 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/RepoLoader.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/RepoLoader.java @@ -1,5 +1,13 @@ package de.robv.android.xposed.installer.util; +import android.content.Context; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -15,13 +23,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPInputStream; -import android.content.Context; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.text.TextUtils; -import android.util.Log; -import android.widget.Toast; import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.XposedApp; import de.robv.android.xposed.installer.repo.Module; @@ -34,29 +35,28 @@ import de.robv.android.xposed.installer.util.DownloadsUtil.SyncDownloadInfo; public class RepoLoader { + private static final int UPDATE_FREQUENCY = 24 * 60 * 60 * 1000; + private static final String DEFAULT_REPOSITORIES = "http://dl.xposed.info/repo/full.xml.gz"; private static RepoLoader mInstance = null; + private final List mListeners = new CopyOnWriteArrayList(); + private final Map mLocalReleaseTypesCache = new HashMap(); private XposedApp mApp = null; private SharedPreferences mPref; private SharedPreferences mModulePref; private ConnectivityManager mConMgr; - private boolean mIsLoading = false; private boolean mReloadTriggeredOnce = false; - private final List mListeners = new CopyOnWriteArrayList(); - - private static final int UPDATE_FREQUENCY = 24 * 60 * 60 * 1000; - private static final String DEFAULT_REPOSITORIES = "http://dl.xposed.info/repo/full.xml.gz"; - private Map mRepositories = null; - + private Map mRepositories = null; private ReleaseType mGlobalReleaseType; - private final Map mLocalReleaseTypesCache = new HashMap(); private RepoLoader() { mInstance = this; mApp = XposedApp.getInstance(); mPref = mApp.getSharedPreferences("repo", Context.MODE_PRIVATE); - mModulePref = mApp.getSharedPreferences("module_settings", Context.MODE_PRIVATE); - mConMgr = (ConnectivityManager) mApp.getSystemService(Context.CONNECTIVITY_SERVICE); + mModulePref = mApp.getSharedPreferences("module_settings", + Context.MODE_PRIVATE); + mConMgr = (ConnectivityManager) mApp + .getSystemService(Context.CONNECTIVITY_SERVICE); mGlobalReleaseType = ReleaseType.fromString(XposedApp.getPreferences() .getString("release_type_global", "stable")); @@ -73,9 +73,11 @@ public static synchronized RepoLoader getInstance() { public boolean refreshRepositories() { mRepositories = RepoDb.getRepositories(); - // Unlikely case (usually only during initial load): DB state doesn't fit to configuration + // Unlikely case (usually only during initial load): DB state doesn't + // fit to configuration boolean needReload = false; - String[] config = mPref.getString("repositories", DEFAULT_REPOSITORIES).split("\\|"); + String[] config = mPref.getString("repositories", DEFAULT_REPOSITORIES) + .split("\\|"); if (mRepositories.size() != config.length) { needReload = true; } else { @@ -136,8 +138,10 @@ private ReleaseType getReleaseTypeLocal(String packageName) { if (mLocalReleaseTypesCache.containsKey(packageName)) return mLocalReleaseTypesCache.get(packageName); - String value = mModulePref.getString(packageName + "_release_type", null); - ReleaseType result = (!TextUtils.isEmpty(value)) ? ReleaseType.fromString(value) : null; + String value = mModulePref.getString(packageName + "_release_type", + null); + ReleaseType result = (!TextUtils.isEmpty(value)) + ? ReleaseType.fromString(value) : null; mLocalReleaseTypesCache.put(packageName, result); return result; } @@ -163,7 +167,9 @@ public ModuleVersion getLatestVersion(Module module) { } public boolean isVersionShown(ModuleVersion version) { - return version.relType.ordinal() <= getMaxShownReleaseType(version.module.packageName).ordinal(); + return version.relType + .ordinal() <= getMaxShownReleaseType(version.module.packageName) + .ordinal(); } public ReleaseType getMaxShownReleaseType(String packageName) { @@ -204,13 +210,15 @@ public void run() { final List messages = new LinkedList(); boolean hasChanged = downloadAndParseFiles(messages); - mPref.edit().putLong("last_update_check", System.currentTimeMillis()).commit(); + mPref.edit().putLong("last_update_check", + System.currentTimeMillis()).commit(); if (!messages.isEmpty()) { XposedApp.runOnUiThread(new Runnable() { public void run() { for (String message : messages) { - Toast.makeText(mApp, message, Toast.LENGTH_LONG).show(); + Toast.makeText(mApp, message, Toast.LENGTH_LONG) + .show(); } } }); @@ -303,9 +311,11 @@ private boolean downloadAndParseFiles(List messages) { ? String.format(repo.partialUrl, repo.version) : repo.url; File cacheFile = getRepoCacheFile(url); - SyncDownloadInfo info = DownloadsUtil.downloadSynchronously(url, cacheFile); + SyncDownloadInfo info = DownloadsUtil.downloadSynchronously(url, + cacheFile); - Log.i(XposedApp.TAG, String.format("Downloaded %s with status %d (error: %s), size %d bytes", + Log.i(XposedApp.TAG, String.format( + "Downloaded %s with status %d (error: %s), size %d bytes", url, info.status, info.errorMessage, cacheFile.length())); if (info.status != SyncDownloadInfo.STATUS_SUCCESS) { @@ -352,12 +362,15 @@ public void onCompleted(Repository repository) { repo.partialUrl = repository.partialUrl; repo.version = repository.version; } else { - RepoDb.updateRepositoryVersion(repoId, repository.version); + RepoDb.updateRepositoryVersion(repoId, + repository.version); repo.version = repository.version; } - Log.i(XposedApp.TAG, String.format("Updated repository %s to version %s (%d new / %d removed modules)", - repo.url, repo.version, insertCounter.get(), deleteCounter.get())); + Log.i(XposedApp.TAG, String.format( + "Updated repository %s to version %s (%d new / %d removed modules)", + repo.url, repo.version, insertCounter.get(), + deleteCounter.get())); } }); @@ -365,22 +378,26 @@ public void onCompleted(Repository repository) { } catch (Throwable t) { Log.e(XposedApp.TAG, "Cannot load repository from " + url, t); - messages.add(mApp.getString(R.string.repo_load_failed, url, t.getMessage())); + messages.add(mApp.getString(R.string.repo_load_failed, url, + t.getMessage())); DownloadsUtil.clearCache(url); } finally { if (in != null) - try { in.close(); } catch (IOException ignored) {} + try { + in.close(); + } catch (IOException ignored) { + } cacheFile.delete(); RepoDb.endTransation(); } } - // TODO Set ModuleColumns.PREFERRED for modules which appear in multiple repositories + // TODO Set ModuleColumns.PREFERRED for modules which appear in multiple + // repositories return hasChanged.get(); } - public void addListener(RepoListener listener, boolean triggerImmediately) { if (!mListeners.contains(listener)) mListeners.add(listener); @@ -401,8 +418,9 @@ private void notifyListeners() { public interface RepoListener { /** - * Called whenever the list of modules from repositories has been successfully reloaded + * Called whenever the list of modules from repositories has been + * successfully reloaded */ - public void onRepoReloaded(RepoLoader loader); + void onRepoReloaded(RepoLoader loader); } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/RootUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/RootUtil.java index 646681e21..d7f93cc43 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/RootUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/RootUtil.java @@ -1,9 +1,10 @@ package de.robv.android.xposed.installer.util; -import java.util.List; - import android.os.Handler; import android.os.HandlerThread; + +import java.util.List; + import eu.chainfire.libsuperuser.Shell; import eu.chainfire.libsuperuser.Shell.OnCommandResultListener; @@ -17,7 +18,8 @@ public class RootUtil { private OnCommandResultListener commandResultListener = new OnCommandResultListener() { @Override - public void onCommandResult(int commandCode, int exitCode, List output) { + public void onCommandResult(int commandCode, int exitCode, + List output) { mLastExitCode = exitCode; mLastOutput = output; synchronized (mCallbackThread) { @@ -32,18 +34,19 @@ private void waitForCommandFinished() { while (mCommandRunning) { try { mCallbackThread.wait(); - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) { + } } } if (mLastExitCode == OnCommandResultListener.WATCHDOG_EXIT - || mLastExitCode == OnCommandResultListener.SHELL_DIED) + || mLastExitCode == OnCommandResultListener.SHELL_DIED) dispose(); } /** - * Starts an interactive shell with root permissions. - * Does nothing if already running. + * Starts an interactive shell with root permissions. Does nothing if + * already running. * * @return true if root access is available, false otherwise */ @@ -59,12 +62,10 @@ public synchronized boolean startShell() { mCallbackThread.start(); mCommandRunning = true; - mShell = new Shell.Builder() - .useSU() - .setHandler(new Handler(mCallbackThread.getLooper())) - .setWantSTDERR(true) - .setWatchdogTimeout(10) - .open(commandResultListener); + mShell = new Shell.Builder().useSU() + .setHandler(new Handler(mCallbackThread.getLooper())) + .setWantSTDERR(true).setWatchdogTimeout(10) + .open(commandResultListener); waitForCommandFinished(); @@ -85,7 +86,8 @@ public synchronized void dispose() { try { mShell.close(); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } mShell = null; mCallbackThread.quit(); @@ -93,7 +95,8 @@ public synchronized void dispose() { } /** - * Executes a single command, waits for its termination and returns the result + * Executes a single command, waits for its termination and returns the + * result */ public synchronized int execute(String command, List output) { if (mShell == null) @@ -114,7 +117,8 @@ public synchronized int execute(String command, List output) { */ public int executeWithBusybox(String command, List output) { AssetUtil.extractBusybox(); - return execute(AssetUtil.BUSYBOX_FILE.getAbsolutePath() + " " + command, output); + return execute(AssetUtil.BUSYBOX_FILE.getAbsolutePath() + " " + command, + output); } @Override diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/ThemeUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/ThemeUtil.java index 0e82c83a8..c22e1ce83 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/ThemeUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/ThemeUtil.java @@ -3,18 +3,19 @@ import android.content.Context; import android.content.res.Resources.Theme; import android.content.res.TypedArray; + import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.XposedApp; import de.robv.android.xposed.installer.XposedBaseActivity; public final class ThemeUtil { - private ThemeUtil() {}; - private static int[] THEMES = new int[] { - R.style.Theme_XposedInstaller_Light, - R.style.Theme_XposedInstaller_Dark, - R.style.Theme_XposedInstaller_Dark_Black, - }; + R.style.Theme_XposedInstaller_Light, + R.style.Theme_XposedInstaller_Dark, + R.style.Theme_XposedInstaller_Dark_Black, }; + + private ThemeUtil() { + } public static int getSelectTheme() { int theme = XposedApp.getPreferences().getInt("theme", 0); @@ -34,7 +35,7 @@ public static void reloadTheme(XposedBaseActivity activity) { public static int getThemeColor(Context context, int id) { Theme theme = context.getTheme(); - TypedArray a = theme.obtainStyledAttributes(new int[] {id}); + TypedArray a = theme.obtainStyledAttributes(new int[] { id }); int result = a.getColor(0, 0); a.recycle(); return result; diff --git a/app/src/main/java/de/robv/android/xposed/installer/util/UIUtil.java b/app/src/main/java/de/robv/android/xposed/installer/util/UIUtil.java index 81187db85..41c106434 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/util/UIUtil.java +++ b/app/src/main/java/de/robv/android/xposed/installer/util/UIUtil.java @@ -3,7 +3,7 @@ import android.os.Build; public class UIUtil { - public static boolean isLollipop() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - } + public static boolean isLollipop() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/widget/DownloadView.java b/app/src/main/java/de/robv/android/xposed/installer/widget/DownloadView.java index e8cdb472f..977c692ef 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/widget/DownloadView.java +++ b/app/src/main/java/de/robv/android/xposed/installer/widget/DownloadView.java @@ -9,29 +9,94 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; + import de.robv.android.xposed.installer.R; import de.robv.android.xposed.installer.util.DownloadsUtil; import de.robv.android.xposed.installer.util.DownloadsUtil.DownloadFinishedCallback; import de.robv.android.xposed.installer.util.DownloadsUtil.DownloadInfo; public class DownloadView extends LinearLayout { - private DownloadInfo mInfo = null; - private String mUrl = null; - private String mTitle = null; - private DownloadFinishedCallback mCallback = null; - private final Button btnDownload; private final Button btnDownloadCancel; private final Button btnInstall; private final ProgressBar progressBar; private final TextView txtInfo; + private DownloadInfo mInfo = null; + private String mUrl = null; + private final Runnable refreshViewRunnable = new Runnable() { + @Override + public void run() { + if (mUrl == null) { + btnDownload.setVisibility(View.GONE); + btnDownloadCancel.setVisibility(View.GONE); + btnInstall.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + txtInfo.setVisibility(View.VISIBLE); + txtInfo.setText(R.string.download_view_no_url); + return; + } else if (mInfo == null) { + btnDownload.setVisibility(View.VISIBLE); + btnDownloadCancel.setVisibility(View.GONE); + btnInstall.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + txtInfo.setVisibility(View.GONE); + } else { + switch (mInfo.status) { + case DownloadManager.STATUS_PENDING: + case DownloadManager.STATUS_PAUSED: + case DownloadManager.STATUS_RUNNING: + btnDownload.setVisibility(View.GONE); + btnDownloadCancel.setVisibility(View.VISIBLE); + btnInstall.setVisibility(View.GONE); + progressBar.setVisibility(View.VISIBLE); + txtInfo.setVisibility(View.VISIBLE); + if (mInfo.totalSize <= 0 + || mInfo.status != DownloadManager.STATUS_RUNNING) { + progressBar.setIndeterminate(true); + txtInfo.setText(R.string.download_view_waiting); + } else { + progressBar.setIndeterminate(false); + progressBar.setMax(mInfo.totalSize); + progressBar.setProgress(mInfo.bytesDownloaded); + txtInfo.setText(getContext().getString( + R.string.download_view_running, + mInfo.bytesDownloaded / 1024, + mInfo.totalSize / 1024)); + } + break; + + case DownloadManager.STATUS_FAILED: + btnDownload.setVisibility(View.VISIBLE); + btnDownloadCancel.setVisibility(View.GONE); + btnInstall.setVisibility(View.GONE); + progressBar.setVisibility(View.GONE); + txtInfo.setVisibility(View.VISIBLE); + txtInfo.setText(getContext().getString( + R.string.download_view_failed, mInfo.reason)); + break; + + case DownloadManager.STATUS_SUCCESSFUL: + btnDownload.setVisibility(View.GONE); + btnDownloadCancel.setVisibility(View.GONE); + btnInstall.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.GONE); + txtInfo.setVisibility(View.VISIBLE); + txtInfo.setText(R.string.download_view_successful); + break; + } + } + } + }; + private String mTitle = null; + private DownloadFinishedCallback mCallback = null; public DownloadView(Context context, AttributeSet attrs) { super(context, attrs); setFocusable(false); setOrientation(LinearLayout.VERTICAL); - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.download_view, this, true); btnDownload = (Button) findViewById(R.id.btnDownload); @@ -41,7 +106,8 @@ public DownloadView(Context context, AttributeSet attrs) { btnDownload.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mInfo = DownloadsUtil.add(getContext(), mTitle, mUrl, mCallback); + mInfo = DownloadsUtil.add(getContext(), mTitle, mUrl, + mCallback); refreshViewFromUiThread(); if (mInfo != null) @@ -84,66 +150,9 @@ private void refreshView() { post(refreshViewRunnable); } - private final Runnable refreshViewRunnable = new Runnable() { - @Override - public void run() { - if (mUrl == null) { - btnDownload.setVisibility(View.GONE); - btnDownloadCancel.setVisibility(View.GONE); - btnInstall.setVisibility(View.GONE); - progressBar.setVisibility(View.GONE); - txtInfo.setVisibility(View.VISIBLE); - txtInfo.setText(R.string.download_view_no_url); - return; - } else if (mInfo == null) { - btnDownload.setVisibility(View.VISIBLE); - btnDownloadCancel.setVisibility(View.GONE); - btnInstall.setVisibility(View.GONE); - progressBar.setVisibility(View.GONE); - txtInfo.setVisibility(View.GONE); - } else { - switch (mInfo.status) { - case DownloadManager.STATUS_PENDING: - case DownloadManager.STATUS_PAUSED: - case DownloadManager.STATUS_RUNNING: - btnDownload.setVisibility(View.GONE); - btnDownloadCancel.setVisibility(View.VISIBLE); - btnInstall.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - txtInfo.setVisibility(View.VISIBLE); - if (mInfo.totalSize <= 0 || mInfo.status != DownloadManager.STATUS_RUNNING) { - progressBar.setIndeterminate(true); - txtInfo.setText(R.string.download_view_waiting); - } else { - progressBar.setIndeterminate(false); - progressBar.setMax(mInfo.totalSize); - progressBar.setProgress(mInfo.bytesDownloaded); - txtInfo.setText(getContext().getString(R.string.download_view_running, - mInfo.bytesDownloaded / 1024, mInfo.totalSize / 1024)); - } - break; - - case DownloadManager.STATUS_FAILED: - btnDownload.setVisibility(View.VISIBLE); - btnDownloadCancel.setVisibility(View.GONE); - btnInstall.setVisibility(View.GONE); - progressBar.setVisibility(View.GONE); - txtInfo.setVisibility(View.VISIBLE); - txtInfo.setText(getContext().getString(R.string.download_view_failed, mInfo.reason)); - break; - - case DownloadManager.STATUS_SUCCESSFUL: - btnDownload.setVisibility(View.GONE); - btnDownloadCancel.setVisibility(View.GONE); - btnInstall.setVisibility(View.VISIBLE); - progressBar.setVisibility(View.GONE); - txtInfo.setVisibility(View.VISIBLE); - txtInfo.setText(R.string.download_view_successful); - break; - } - } - } - }; + public String getUrl() { + return mUrl; + } public void setUrl(String url) { mUrl = url; @@ -156,26 +165,23 @@ public void setUrl(String url) { refreshView(); } - public String getUrl() { - return mUrl; + public String getTitle() { + return mTitle; } public void setTitle(String title) { this.mTitle = title; } - public String getTitle() { - return mTitle; + public DownloadFinishedCallback getDownloadFinishedCallback() { + return mCallback; } - public void setDownloadFinishedCallback(DownloadFinishedCallback downloadFinishedCallback) { + public void setDownloadFinishedCallback( + DownloadFinishedCallback downloadFinishedCallback) { this.mCallback = downloadFinishedCallback; } - public DownloadFinishedCallback getDownloadFinishedCallback() { - return mCallback; - } - private class DownloadMonitor extends Thread { public DownloadMonitor() { super("DownloadMonitor"); @@ -196,8 +202,8 @@ public void run() { return; if (mInfo.status != DownloadManager.STATUS_PENDING - && mInfo.status != DownloadManager.STATUS_PAUSED - && mInfo.status != DownloadManager.STATUS_RUNNING) + && mInfo.status != DownloadManager.STATUS_PAUSED + && mInfo.status != DownloadManager.STATUS_RUNNING) return; } } diff --git a/app/src/main/java/de/robv/android/xposed/installer/widget/IntegerListPreference.java b/app/src/main/java/de/robv/android/xposed/installer/widget/IntegerListPreference.java index d31b19673..13a137de7 100644 --- a/app/src/main/java/de/robv/android/xposed/installer/widget/IntegerListPreference.java +++ b/app/src/main/java/de/robv/android/xposed/installer/widget/IntegerListPreference.java @@ -14,6 +14,15 @@ public IntegerListPreference(Context context, AttributeSet attrs) { super(context, attrs); } + public static int getIntValue(String value) { + if (value == null) + return 0; + + return (int) ((value.startsWith("0x")) + ? Long.parseLong(value.substring(2), 16) + : Long.parseLong(value)); + } + @Override public void setValue(String value) { super.setValue(value); @@ -51,13 +60,4 @@ public int findIndexOfValue(String value) { } return -1; } - - public static int getIntValue(String value) { - if (value == null) - return 0; - - return (int)((value.startsWith("0x")) - ? Long.parseLong(value.substring(2), 16) - : Long.parseLong(value)); - } } diff --git a/app/src/main/res/anim/slide_in_left.xml b/app/src/main/res/anim/slide_in_left.xml index 6b75c9f1f..7128c3bfe 100644 --- a/app/src/main/res/anim/slide_in_left.xml +++ b/app/src/main/res/anim/slide_in_left.xml @@ -1,9 +1,9 @@ - + + android:toXDelta="0"/> \ No newline at end of file diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml index fca3c630a..ec69b01d1 100644 --- a/app/src/main/res/anim/slide_in_right.xml +++ b/app/src/main/res/anim/slide_in_right.xml @@ -1,9 +1,9 @@ - + + android:toXDelta="0"/> \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml index cb58b58b3..8c1d45fcc 100644 --- a/app/src/main/res/anim/slide_out_left.xml +++ b/app/src/main/res/anim/slide_out_left.xml @@ -1,9 +1,9 @@ - + + android:toXDelta="-100%p"/> \ No newline at end of file diff --git a/app/src/main/res/anim/slide_out_right.xml b/app/src/main/res/anim/slide_out_right.xml index f39f52e9b..180636a46 100644 --- a/app/src/main/res/anim/slide_out_right.xml +++ b/app/src/main/res/anim/slide_out_right.xml @@ -1,9 +1,9 @@ - + + android:toXDelta="100%p"/> \ No newline at end of file diff --git a/app/src/main/res/drawable/background_card_black.xml b/app/src/main/res/drawable/background_card_black.xml index 5f1648458..63cc99e37 100644 --- a/app/src/main/res/drawable/background_card_black.xml +++ b/app/src/main/res/drawable/background_card_black.xml @@ -1,7 +1,7 @@ - - + + diff --git a/app/src/main/res/drawable/background_card_dark.xml b/app/src/main/res/drawable/background_card_dark.xml index 87ebd7666..4c88a51d1 100644 --- a/app/src/main/res/drawable/background_card_dark.xml +++ b/app/src/main/res/drawable/background_card_dark.xml @@ -1,7 +1,7 @@ - - + + diff --git a/app/src/main/res/drawable/background_card_light.xml b/app/src/main/res/drawable/background_card_light.xml index 18a239158..026baa95f 100644 --- a/app/src/main/res/drawable/background_card_light.xml +++ b/app/src/main/res/drawable/background_card_light.xml @@ -1,7 +1,7 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_card_normal_black.xml b/app/src/main/res/drawable/background_card_normal_black.xml index 36fc1a0bb..0f59ec586 100644 --- a/app/src/main/res/drawable/background_card_normal_black.xml +++ b/app/src/main/res/drawable/background_card_normal_black.xml @@ -3,8 +3,9 @@ - + @@ -14,14 +15,16 @@ - + - diff --git a/app/src/main/res/drawable/background_card_normal_dark.xml b/app/src/main/res/drawable/background_card_normal_dark.xml index e4752ebda..8817501fa 100644 --- a/app/src/main/res/drawable/background_card_normal_dark.xml +++ b/app/src/main/res/drawable/background_card_normal_dark.xml @@ -3,8 +3,9 @@ - + @@ -14,14 +15,16 @@ - + - diff --git a/app/src/main/res/drawable/background_card_normal_light.xml b/app/src/main/res/drawable/background_card_normal_light.xml index 171173b20..4740f5a91 100644 --- a/app/src/main/res/drawable/background_card_normal_light.xml +++ b/app/src/main/res/drawable/background_card_normal_light.xml @@ -3,8 +3,9 @@ - + @@ -14,14 +15,16 @@ - + - diff --git a/app/src/main/res/drawable/background_card_pressed_black.xml b/app/src/main/res/drawable/background_card_pressed_black.xml index 5ad08b4c7..a9dfaf498 100644 --- a/app/src/main/res/drawable/background_card_pressed_black.xml +++ b/app/src/main/res/drawable/background_card_pressed_black.xml @@ -3,28 +3,31 @@ - + - + - + - + - + - + diff --git a/app/src/main/res/drawable/background_card_pressed_dark.xml b/app/src/main/res/drawable/background_card_pressed_dark.xml index f930a6bb8..37d662742 100644 --- a/app/src/main/res/drawable/background_card_pressed_dark.xml +++ b/app/src/main/res/drawable/background_card_pressed_dark.xml @@ -3,28 +3,31 @@ - + - + - + - + - + - + diff --git a/app/src/main/res/drawable/background_card_pressed_light.xml b/app/src/main/res/drawable/background_card_pressed_light.xml index 41b90227a..471984f04 100644 --- a/app/src/main/res/drawable/background_card_pressed_light.xml +++ b/app/src/main/res/drawable/background_card_pressed_light.xml @@ -3,28 +3,31 @@ - + - + - + - + - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_container.xml b/app/src/main/res/layout/activity_container.xml index ddf6adcb2..fe386c5db 100644 --- a/app/src/main/res/layout/activity_container.xml +++ b/app/src/main/res/layout/activity_container.xml @@ -1,10 +1,10 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:windowBackground" + android:orientation="vertical"> + app:popupTheme="@style/ThemeOverlay.AppCompat.Light" + app:theme="@style/Theme.XposedInstaller.Toolbar"/> + android:layout_weight="1"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_download_details.xml b/app/src/main/res/layout/activity_download_details.xml index 46fbe6ae0..ee2670d1c 100644 --- a/app/src/main/res/layout/activity_download_details.xml +++ b/app/src/main/res/layout/activity_download_details.xml @@ -1,32 +1,32 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:elevation="@dimen/toolbar_elevation"> + app:theme="@style/Theme.XposedInstaller.Toolbar"/> + app:tabMode="scrollable" + app:tabTextAppearance="@style/TextAppearance.Design.Tab"/> @@ -35,7 +35,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="?attr/actionBarSize" - app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + app:layout_behavior="@string/appbar_scrolling_view_behavior"/> + android:textStyle="italic"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_download_details_not_found.xml b/app/src/main/res/layout/activity_download_details_not_found.xml index fe33e010b..f537c47f8 100644 --- a/app/src/main/res/layout/activity_download_details_not_found.xml +++ b/app/src/main/res/layout/activity_download_details_not_found.xml @@ -1,12 +1,12 @@ + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" + android:padding="8dp" + tools:context=".DownloadDetailsActivity"> + android:textAppearance="?android:attr/textAppearanceMedium"/>