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 f8e7ea44..90ca0f73 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 @@ -16,11 +16,11 @@ import static de.robv.android.xposed.installer.util.InstallZipUtil.parseXposedPr public class XposedApp extends Application { public static final String TAG = "XposedApp"; private static final File EDXPOSED_PROP_FILE = new File("/system/framework/edconfig.jar"); - private static XposedApp mInstance = null; - public InstallZipUtil.XposedProp mXposedProp; + private static XposedApp instance = null; + public InstallZipUtil.XposedProp xposedProp; public static XposedApp getInstance() { - return mInstance; + return instance; } // This method is hooked by XposedBridge to return the current version @@ -31,7 +31,7 @@ public class XposedApp extends Application { public void onCreate() { super.onCreate(); - mInstance = this; + instance = this; reloadXposedProp(); } @@ -51,7 +51,7 @@ public class XposedApp extends Application { } } synchronized (this) { - mXposedProp = prop; + xposedProp = prop; } } } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java index d98c28de..24c27f8a 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java @@ -66,7 +66,7 @@ public class BaseActivity extends AppCompatActivity { protected void setupWindowInsets(View rootView, View secondView) { rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> { - if (secondView != null) { + if (secondView != null && insets.getTappableElementInsets().bottom != insets.getSystemWindowInsetBottom()) { secondView.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); } rootView.setPadding(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getTappableElementInsets().bottom); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/BlackListActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/BlackListActivity.java index 5bdc42f8..b8ff2932 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/BlackListActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/BlackListActivity.java @@ -3,6 +3,7 @@ package org.meowcat.edxposed.manager; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.os.Bundle; +import android.os.Handler; import android.view.Menu; import android.view.View; @@ -17,15 +18,22 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import org.meowcat.edxposed.manager.adapters.AppAdapter; import org.meowcat.edxposed.manager.adapters.AppHelper; -import org.meowcat.edxposed.manager.adapters.CompatListAdapter; +import org.meowcat.edxposed.manager.adapters.BlackListAdapter; import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding; public class BlackListActivity extends BaseActivity implements AppAdapter.Callback { private SearchView searchView; - private CompatListAdapter appAdapter; + private BlackListAdapter appAdapter; private SearchView.OnQueryTextListener searchListener; private ActivityBlackListBinding binding; + private Runnable runnable = new Runnable() { + @Override + public void run() { + binding.swipeRefreshLayout.setRefreshing(true); + } + }; + private Handler handler = new Handler(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -40,16 +48,17 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba } setupWindowInsets(binding.snackbar, binding.recyclerView); binding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); - appAdapter = new CompatListAdapter(this); + final boolean isWhiteListMode = isWhiteListMode(); + appAdapter = new BlackListAdapter(this, isWhiteListMode, binding); binding.recyclerView.setAdapter(appAdapter); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL); binding.recyclerView.addItemDecoration(dividerItemDecoration); appAdapter.setCallback(this); - - binding.swipeRefreshLayout.setRefreshing(true); + handler.postDelayed(runnable, 300); binding.swipeRefreshLayout.setOnRefreshListener(appAdapter::refresh); + searchListener = new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { @@ -110,6 +119,7 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba @Override public void onDataReady() { + handler.removeCallbacks(runnable); binding.swipeRefreshLayout.setRefreshing(false); String queryStr = searchView != null ? searchView.getQuery().toString() : ""; appAdapter.filter(queryStr); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/CompatListActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/CompatListActivity.java index 93da5817..f0a32f33 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/CompatListActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/CompatListActivity.java @@ -38,7 +38,7 @@ public class CompatListActivity extends BaseActivity implements AppAdapter.Callb } setupWindowInsets(binding.snackbar, binding.recyclerView); binding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); - appAdapter = new CompatListAdapter(this); + appAdapter = new CompatListAdapter(this, binding); binding.recyclerView.setAdapter(appAdapter); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java index e9fb8bdb..566b177b 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java @@ -25,6 +25,7 @@ import androidx.appcompat.widget.SearchView; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.transition.TransitionManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersAdapter; @@ -173,6 +174,7 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis private void reloadItems() { runOnUiThread(() -> { adapter.swapCursor(RepoDb.queryModuleOverview(sortingOrder, filterText)); + TransitionManager.beginDelayedTransition(binding.recyclerView); adapter.notifyDataSetChanged(); }); } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsFragment.java b/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsFragment.java index 908e8746..cb4e962f 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsFragment.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsFragment.java @@ -36,7 +36,9 @@ public class DownloadDetailsFragment extends Fragment { } DownloadDetailsBinding binding = DownloadDetailsBinding.inflate(inflater, container, false); ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> { - binding.getRoot().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + if (insets.getTappableElementInsets().bottom != insets.getSystemWindowInsetBottom()) { + binding.getRoot().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + } return insets; }); binding.downloadTitle.setText(module.name); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java b/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java index 90b1aa0e..cb8363bd 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java @@ -92,7 +92,9 @@ public class DownloadDetailsVersionsFragment extends ListFragment { getListView().setClipToPadding(false); getListView().setClipToPadding(false); ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { - getListView().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + if (insets.getTappableElementInsets().bottom != insets.getSystemWindowInsetBottom()) { + getListView().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + } return insets; }); } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/EdDownloadActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/EdDownloadActivity.java index bc104536..9abd0e52 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/EdDownloadActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/EdDownloadActivity.java @@ -12,6 +12,7 @@ import androidx.appcompat.app.ActionBar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; +import androidx.transition.TransitionManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.gson.Gson; @@ -93,6 +94,7 @@ public class EdDownloadActivity extends BaseActivity { try { final JSONUtils.XposedJson xposedJson = new Gson().fromJson(result, JSONUtils.XposedJson.class); + TransitionManager.beginDelayedTransition(binding.tabLayout); for (XposedTab tab : xposedJson.tabs) { if (tab.sdks.contains(Build.VERSION.SDK_INT)) { tabsAdapter.addFragment(tab.name, BaseAdvancedInstaller.newInstance(tab)); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/LogsActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/LogsActivity.java index 851c981b..dac68f6f 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/LogsActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/LogsActivity.java @@ -237,7 +237,7 @@ public class LogsActivity extends BaseActivity { mProgressDialog = new MaterialAlertDialogBuilder(LogsActivity.this).create(); mProgressDialog.setMessage(getString(R.string.loading)); mProgressDialog.setCancelable(false); - handler.postDelayed(mRunnable, 500); + handler.postDelayed(mRunnable, 300); } @Override diff --git a/app/src/main/java/org/meowcat/edxposed/manager/MainActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/MainActivity.java index 0f566a88..2d928113 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/MainActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/MainActivity.java @@ -13,7 +13,7 @@ import org.meowcat.edxposed.manager.util.RepoLoader; public class MainActivity extends BaseActivity implements RepoLoader.RepoListener, ModuleUtil.ModuleListener { ActivityMainBinding binding; - private RepoLoader mRepoLoader; + private RepoLoader repoLoader; @SuppressLint("PrivateResource") @Override @@ -21,10 +21,10 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - - mRepoLoader = RepoLoader.getInstance(); + setupWindowInsets(binding.snackbar, binding.nestedScrollView); + repoLoader = RepoLoader.getInstance(); ModuleUtil.getInstance().addListener(this); - mRepoLoader.addListener(this, false); + repoLoader.addListener(this, false); binding.modules.setOnClickListener(v -> { Intent intent = new Intent(); intent.setClass(getApplicationContext(), ModulesActivity.class); @@ -110,8 +110,8 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene private void notifyDataSetChanged() { runOnUiThread(() -> { - String frameworkUpdateVersion = mRepoLoader.getFrameworkUpdateVersion(); - boolean moduleUpdateAvailable = mRepoLoader.hasModuleUpdates(); + String frameworkUpdateVersion = repoLoader.getFrameworkUpdateVersion(); + boolean moduleUpdateAvailable = repoLoader.hasModuleUpdates(); ModuleUtil.getInstance().getEnabledModules().size(); binding.modulesSummary.setText(String.format(getString(R.string.ModulesDetail), ModuleUtil.getInstance().getEnabledModules().size())); if (frameworkUpdateVersion != null) { @@ -145,7 +145,7 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene protected void onDestroy() { super.onDestroy(); ModuleUtil.getInstance().removeListener(this); - mRepoLoader.removeListener(this); + repoLoader.removeListener(this); } } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java index 916b0109..9fd39c93 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java @@ -22,6 +22,7 @@ import androidx.appcompat.widget.SwitchCompat; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.transition.TransitionManager; import com.google.android.material.snackbar.Snackbar; @@ -86,6 +87,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi } } adapter.addAll(showList); + TransitionManager.beginDelayedTransition(binding.recyclerView); adapter.notifyDataSetChanged(); moduleUtil.updateModulesList(false); binding.swipeRefreshLayout.setRefreshing(false); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/SettingsActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/SettingsActivity.java index 9731faa2..90e4974e 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/SettingsActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/SettingsActivity.java @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; import android.os.FileUtils; import android.view.View; @@ -344,7 +345,7 @@ public class SettingsActivity extends BaseActivity { transparent.setOnPreferenceChangeListener((preference, newValue) -> { boolean enabled = (Boolean) newValue; Activity activity = getActivity(); - if (activity != null && !XposedApp.getPreferences().getBoolean("black_dark_theme", false)) { + if (activity != null && activity.getWindow().getStatusBarColor() != Color.BLACK) { if (enabled) { activity.getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.colorActionBar)); } else { @@ -408,7 +409,9 @@ public class SettingsActivity extends BaseActivity { ((FrameLayout) getListView().getParent()).setClipChildren(false); ((FrameLayout) getListView().getParent()).setClipToPadding(false); ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { - getListView().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + if (insets.getTappableElementInsets().bottom != insets.getSystemWindowInsetBottom()) { + getListView().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom()); + } return insets; }); } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java b/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java index 0343ec1e..851aef9f 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java @@ -60,7 +60,7 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem } public static InstallZipUtil.XposedProp getXposedProp() { - return de.robv.android.xposed.installer.XposedApp.getInstance().mXposedProp; + return de.robv.android.xposed.installer.XposedApp.getInstance().xposedProp; } public static void runOnUiThread(Runnable action) { diff --git a/app/src/main/java/org/meowcat/edxposed/manager/adapters/AppAdapter.java b/app/src/main/java/org/meowcat/edxposed/manager/adapters/AppAdapter.java index f400fc18..46f2875e 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/adapters/AppAdapter.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/adapters/AppAdapter.java @@ -16,9 +16,11 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.widget.SwitchCompat; import androidx.recyclerview.widget.RecyclerView; +import androidx.transition.TransitionManager; import org.meowcat.edxposed.manager.R; import org.meowcat.edxposed.manager.XposedApp; +import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding; import org.meowcat.edxposed.manager.util.InstallApkUtil; import java.text.DateFormat; @@ -41,9 +43,11 @@ public class AppAdapter extends RecyclerView.Adapter { private PackageManager pm; private ApplicationFilter filter; private Comparator cmp; + private ActivityBlackListBinding binding; - AppAdapter(Context context) { + AppAdapter(Context context, ActivityBlackListBinding binding) { this.context = context; + this.binding = binding; fullList = showList = Collections.emptyList(); checkedList = Collections.emptyList(); filter = new ApplicationFilter(); @@ -262,6 +266,7 @@ public class AppAdapter extends RecyclerView.Adapter { @Override protected void publishResults(CharSequence constraint, FilterResults results) { + TransitionManager.beginDelayedTransition(binding.recyclerView); notifyDataSetChanged(); } } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/adapters/BlackListAdapter.java b/app/src/main/java/org/meowcat/edxposed/manager/adapters/BlackListAdapter.java index d4a829cf..82f0244b 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/adapters/BlackListAdapter.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/adapters/BlackListAdapter.java @@ -6,6 +6,7 @@ import android.widget.CompoundButton; import org.meowcat.edxposed.manager.R; import org.meowcat.edxposed.manager.XposedApp; +import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding; import org.meowcat.edxposed.manager.util.ModuleUtil; import org.meowcat.edxposed.manager.util.ToastUtil; @@ -18,8 +19,8 @@ public class BlackListAdapter extends AppAdapter { private volatile boolean isWhiteListMode; private List checkedList; - public BlackListAdapter(Context context, boolean isWhiteListMode) { - super(context); + public BlackListAdapter(Context context, boolean isWhiteListMode, ActivityBlackListBinding binding) { + super(context, binding); this.isWhiteListMode = isWhiteListMode; } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/adapters/CompatListAdapter.java b/app/src/main/java/org/meowcat/edxposed/manager/adapters/CompatListAdapter.java index 20272096..ed90b8dd 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/adapters/CompatListAdapter.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/adapters/CompatListAdapter.java @@ -5,6 +5,7 @@ import android.content.pm.ApplicationInfo; import android.widget.CompoundButton; import org.meowcat.edxposed.manager.R; +import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding; import org.meowcat.edxposed.manager.util.ToastUtil; import java.util.List; @@ -13,8 +14,8 @@ public class CompatListAdapter extends AppAdapter { private List checkedList; - public CompatListAdapter(Context context) { - super(context); + public CompatListAdapter(Context context, ActivityBlackListBinding binding) { + super(context, binding); } @Override diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/DownloadsUtil.java b/app/src/main/java/org/meowcat/edxposed/manager/util/DownloadsUtil.java index 2c48b650..969f6000 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/util/DownloadsUtil.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/DownloadsUtil.java @@ -1,6 +1,5 @@ package org.meowcat.edxposed.manager.util; -import android.annotation.SuppressLint; import android.app.DownloadManager; import android.app.DownloadManager.Query; import android.app.DownloadManager.Request; @@ -34,31 +33,28 @@ import java.util.Objects; public class DownloadsUtil { public static final String MIME_TYPE_APK = "application/vnd.android.package-archive"; //private static final String MIME_TYPE_ZIP = "application/zip"; - private static final Map mCallbacks = new HashMap<>(); - @SuppressLint("StaticFieldLeak") - private static final XposedApp mApp = XposedApp.getInstance(); - private static final SharedPreferences mPref = mApp - .getSharedPreferences("download_cache", Context.MODE_PRIVATE); + private static final Map callbacks = new HashMap<>(); + private static final SharedPreferences pref = XposedApp.getInstance().getSharedPreferences("download_cache", Context.MODE_PRIVATE); private static DownloadInfo add(Builder b) { - Context context = b.mContext; - removeAllForUrl(context, b.mUrl); + Context context = b.context; + removeAllForUrl(context, b.url); - synchronized (mCallbacks) { - mCallbacks.put(b.mUrl, b.mCallback); + synchronized (callbacks) { + callbacks.put(b.url, b.callback); } - Request request = new Request(Uri.parse(b.mUrl)); - request.setTitle(b.mTitle); - request.setMimeType(b.mMimeType.toString()); + Request request = new Request(Uri.parse(b.url)); + request.setTitle(b.title); + request.setMimeType(b.mimeType.toString()); /*if (b.mSave) { try { - request.setDestinationInExternalPublicDir(savePath, b.mTitle + b.mMimeType.getExtension()); + request.setDestinationInExternalPublicDir(savePath, b.title + b.mimeType.getExtension()); } catch (IllegalStateException e) { Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show(); } } else */ - File destination = new File(context.getExternalCacheDir(), "/downloads/" + b.mTitle + b.mMimeType.getExtension()); + File destination = new File(context.getExternalCacheDir(), "/downloads/" + b.title + b.mimeType.getExtension()); removeAllForLocalFile(context, destination); request.setDestinationUri(Uri.fromFile(destination)); request.setNotificationVisibility(Request.VISIBILITY_VISIBLE); @@ -295,8 +291,8 @@ public class DownloadsUtil { return; DownloadFinishedCallback callback; - synchronized (mCallbacks) { - callback = mCallbacks.get(info.url); + synchronized (callbacks) { + callback = callbacks.get(info.url); } if (callback == null) @@ -345,8 +341,8 @@ public class DownloadsUtil { } if (useNotModifiedTags) { - String modified = mPref.getString("download_" + url + "_modified", null); - String etag = mPref.getString("download_" + url + "_etag", null); + String modified = pref.getString("download_" + url + "_modified", null); + String etag = pref.getString("download_" + url + "_etag", null); if (modified != null) { connection.addRequestProperty("If-Modified-Since", modified); @@ -366,7 +362,7 @@ public class DownloadsUtil { 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, + XposedApp.getInstance().getString(R.string.repo_download_failed_http, url, responseCode, httpConnection.getResponseMessage())); } @@ -385,7 +381,7 @@ public class DownloadsUtil { String modified = httpConnection.getHeaderField("Last-Modified"); String etag = httpConnection.getHeaderField("ETag"); - mPref.edit() + pref.edit() .putString("download_" + url + "_modified", modified) .putString("download_" + url + "_etag", etag).apply(); } @@ -394,7 +390,7 @@ public class DownloadsUtil { } catch (Throwable t) { return new SyncDownloadInfo(SyncDownloadInfo.STATUS_FAILED, - mApp.getString(R.string.repo_download_failed, url, + XposedApp.getInstance().getString(R.string.repo_download_failed, url, t.getMessage())); } finally { @@ -415,10 +411,10 @@ public class DownloadsUtil { static void clearCache(String url) { if (url != null) { - mPref.edit().remove("download_" + url + "_modified") + pref.edit().remove("download_" + url + "_modified") .remove("download_" + url + "_etag").apply(); } else { - mPref.edit().clear().apply(); + pref.edit().clear().apply(); } } @@ -453,39 +449,39 @@ public class DownloadsUtil { } public static class Builder { - private final Context mContext; - boolean mModule = false; - private String mTitle = null; - private String mUrl = null; - private DownloadFinishedCallback mCallback = null; - private MIME_TYPES mMimeType = MIME_TYPES.APK; + private final Context context; + boolean module = false; + private String title = null; + private String url = null; + private DownloadFinishedCallback callback = null; + private MIME_TYPES mimeType = MIME_TYPES.APK; public Builder(Context context) { - mContext = context; + this.context = context; } public Builder setTitle(String title) { - mTitle = title; + this.title = title; return this; } public Builder setUrl(String url) { - mUrl = url; + this.url = url; return this; } public Builder setCallback(DownloadFinishedCallback callback) { - mCallback = callback; + this.callback = callback; return this; } - Builder setMimeType(@SuppressWarnings("SameParameterValue") MIME_TYPES mimeType) { - mMimeType = mimeType; + Builder setMimeType(MIME_TYPES mimeType) { + this.mimeType = mimeType; return this; } public Builder setModule(boolean module) { - this.mModule = module; + this.module = module; return this; } diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/ModuleUtil.java b/app/src/main/java/org/meowcat/edxposed/manager/util/ModuleUtil.java index 93d113df..5be6c507 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/util/ModuleUtil.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/ModuleUtil.java @@ -35,30 +35,28 @@ public final class ModuleUtil { private static final String MODULES_LIST_FILE = XposedApp.BASE_DIR + "conf/modules.list"; private static final String PLAY_STORE_PACKAGE = "com.android.vending"; public static int MIN_MODULE_VERSION = 2; // reject modules with - private static ModuleUtil mInstance = null; - private final XposedApp mApp; - 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 Toast mToast; + private static ModuleUtil instance = null; + private final PackageManager pm; + private final String frameworkPackageName; + private final List listeners = new CopyOnWriteArrayList<>(); + private SharedPreferences pref; + private InstalledModule framework = null; + private Map installedModules; + private boolean isReloading = false; + private Toast toast; private ModuleUtil() { - mApp = XposedApp.getInstance(); - mPref = mApp.getSharedPreferences("enabled_modules", Context.MODE_PRIVATE); - mPm = mApp.getPackageManager(); - mFrameworkPackageName = mApp.getPackageName(); + pref = XposedApp.getInstance().getSharedPreferences("enabled_modules", Context.MODE_PRIVATE); + pm = XposedApp.getInstance().getPackageManager(); + frameworkPackageName = XposedApp.getInstance().getPackageName(); } public static synchronized ModuleUtil getInstance() { - if (mInstance == null) { - mInstance = new ModuleUtil(); - mInstance.reloadInstalledModules(); + if (instance == null) { + instance = new ModuleUtil(); + instance.reloadInstalledModules(); } - return mInstance; + return instance; } public static int extractIntPart(String str) { @@ -76,9 +74,9 @@ public final class ModuleUtil { @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") public void reloadInstalledModules() { synchronized (this) { - if (mIsReloading) + if (isReloading) return; - mIsReloading = true; + isReloading = true; } Map modules = new HashMap<>(); @@ -86,7 +84,7 @@ public final class ModuleUtil { try { RepoDb.deleteAllInstalledModules(); - for (PackageInfo pkg : mPm.getInstalledPackages(PackageManager.GET_META_DATA)) { + for (PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_META_DATA)) { ApplicationInfo app = pkg.applicationInfo; if (!app.enabled) continue; @@ -96,7 +94,7 @@ public final class ModuleUtil { installed = new InstalledModule(pkg, false); modules.put(pkg.packageName, installed); } else if (isFramework(pkg.packageName)) { - mFramework = installed = new InstalledModule(pkg, true); + framework = installed = new InstalledModule(pkg, true); } if (installed != null) @@ -108,25 +106,25 @@ public final class ModuleUtil { RepoDb.endTransation(); } - mInstalledModules = modules; + installedModules = modules; synchronized (this) { - mIsReloading = false; + isReloading = false; } - for (ModuleListener listener : mListeners) { - listener.onInstalledModulesReloaded(mInstance); + for (ModuleListener listener : listeners) { + listener.onInstalledModulesReloaded(instance); } } public InstalledModule reloadSingleModule(String packageName) { PackageInfo pkg; try { - pkg = mPm.getPackageInfo(packageName, PackageManager.GET_META_DATA); + pkg = pm.getPackageInfo(packageName, PackageManager.GET_META_DATA); } catch (NameNotFoundException e) { RepoDb.deleteInstalledModule(packageName); - InstalledModule old = mInstalledModules.remove(packageName); + InstalledModule old = installedModules.remove(packageName); if (old != null) { - for (ModuleListener listener : mListeners) { - listener.onSingleInstalledModuleReloaded(mInstance, packageName, null); + for (ModuleListener listener : listeners) { + listener.onSingleInstalledModuleReloaded(instance, packageName, null); } } return null; @@ -136,18 +134,18 @@ public final class ModuleUtil { 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, + installedModules.put(packageName, module); + for (ModuleListener listener : listeners) { + listener.onSingleInstalledModuleReloaded(instance, packageName, module); } return module; } else { RepoDb.deleteInstalledModule(packageName); - InstalledModule old = mInstalledModules.remove(packageName); + InstalledModule old = installedModules.remove(packageName); if (old != null) { - for (ModuleListener listener : mListeners) { - listener.onSingleInstalledModuleReloaded(mInstance, packageName, null); + for (ModuleListener listener : listeners) { + listener.onSingleInstalledModuleReloaded(instance, packageName, null); } } return null; @@ -155,49 +153,49 @@ public final class ModuleUtil { } public synchronized boolean isLoading() { - return mIsReloading; + return isReloading; } public InstalledModule getFramework() { - return mFramework; + return framework; } public String getFrameworkPackageName() { - return mFrameworkPackageName; + return frameworkPackageName; } private boolean isFramework(String packageName) { - return mFrameworkPackageName.equals(packageName); + return frameworkPackageName.equals(packageName); } // public boolean isInstalled(String packageName) { -// return mInstalledModules.containsKey(packageName) || isFramework(packageName); +// return installedModules.containsKey(packageName) || isFramework(packageName); // } public InstalledModule getModule(String packageName) { - return mInstalledModules.get(packageName); + return installedModules.get(packageName); } public Map getModules() { - return mInstalledModules; + return installedModules; } public void setModuleEnabled(String packageName, boolean enabled) { if (enabled) { - mPref.edit().putInt(packageName, 1).apply(); + pref.edit().putInt(packageName, 1).apply(); } else { - mPref.edit().remove(packageName).apply(); + pref.edit().remove(packageName).apply(); } } public boolean isModuleEnabled(String packageName) { - return mPref.contains(packageName); + return pref.contains(packageName); } public List getEnabledModules() { LinkedList result = new LinkedList<>(); - for (String packageName : mPref.getAll().keySet()) { + for (String packageName : pref.getAll().keySet()) { InstalledModule module = getModule(packageName); if (module != null) result.add(module); @@ -213,7 +211,7 @@ public final class ModuleUtil { Log.i(XposedApp.TAG, "ModuleUtil -> updating modules.list"); int installedXposedVersion = XposedApp.getXposedVersion(); if (!XposedApp.getPreferences().getBoolean("skip_xposedminversion_check", false) && installedXposedVersion <= 0 && showToast) { - Toast.makeText(mApp, R.string.notinstalled, Toast.LENGTH_SHORT).show(); + Toast.makeText(XposedApp.getInstance(), R.string.notinstalled, Toast.LENGTH_SHORT).show(); return; } @@ -223,14 +221,14 @@ public final class ModuleUtil { for (InstalledModule module : enabledModules) { if (!XposedApp.getPreferences().getBoolean("skip_xposedminversion_check", false) && (module.minVersion > installedXposedVersion || module.minVersion < MIN_MODULE_VERSION) && showToast) { - Toast.makeText(mApp, R.string.notinstalled, Toast.LENGTH_SHORT).show(); + Toast.makeText(XposedApp.getInstance(), R.string.notinstalled, Toast.LENGTH_SHORT).show(); continue; } modulesList.println(module.app.sourceDir); try { - String installer = mPm.getInstallerPackageName(module.app.packageName); + String installer = pm.getInstallerPackageName(module.app.packageName); if (!PLAY_STORE_PACKAGE.equals(installer)) enabledModulesList.println(module.app.packageName); } catch (Exception ignored) { @@ -247,27 +245,27 @@ public final class ModuleUtil { } } catch (IOException e) { Log.e(XposedApp.TAG, "ModuleUtil -> cannot write " + MODULES_LIST_FILE, e); - Toast.makeText(mApp, "cannot write " + MODULES_LIST_FILE + e, Toast.LENGTH_SHORT).show(); + Toast.makeText(XposedApp.getInstance(), "cannot write " + MODULES_LIST_FILE + e, Toast.LENGTH_SHORT).show(); } } @SuppressWarnings("SameParameterValue") private void showToast(int message) { - if (mToast != null) { - mToast.cancel(); - mToast = null; + if (toast != null) { + toast.cancel(); + toast = null; } - mToast = Toast.makeText(mApp, mApp.getString(message), Toast.LENGTH_SHORT); - mToast.show(); + toast = Toast.makeText(XposedApp.getInstance(), XposedApp.getInstance().getString(message), Toast.LENGTH_SHORT); + toast.show(); } public void addListener(ModuleListener listener) { - if (!mListeners.contains(listener)) - mListeners.add(listener); + if (!listeners.contains(listener)) + listeners.add(listener); } public void removeListener(ModuleListener listener) { - mListeners.remove(listener); + listeners.remove(listener); } public interface ModuleListener { @@ -337,7 +335,7 @@ public final class ModuleUtil { public String getAppName() { if (appName == null) - appName = app.loadLabel(mPm).toString(); + appName = app.loadLabel(pm).toString(); return appName; } @@ -351,7 +349,7 @@ public final class ModuleUtil { try { int resId = (Integer) descriptionRaw; if (resId != 0) - descriptionTmp = mPm.getResourcesForApplication(app).getString(resId).trim(); + descriptionTmp = pm.getResourcesForApplication(app).getString(resId).trim(); } catch (Exception ignored) { } } @@ -371,13 +369,13 @@ public final class ModuleUtil { Intent mIntent = new Intent(Intent.ACTION_MAIN); //mIntent.addCategory(ModulesFragment.SETTINGS_CATEGORY); mIntent.setPackage(app.packageName); - List ris = mPm.queryIntentActivities(mIntent, 0); + List ris = pm.queryIntentActivities(mIntent, 0); Drawable result; if (ris == null || ris.size() <= 0) - result = app.loadIcon(mPm); + result = app.loadIcon(pm); else - result = ris.get(0).activityInfo.loadIcon(mPm); + result = ris.get(0).activityInfo.loadIcon(pm); iconCache = result.getConstantState(); return result; diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java b/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java index e8d571a9..e7ea200b 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/NotificationUtil.java @@ -1,5 +1,6 @@ package org.meowcat.edxposed.manager.util; +import android.annotation.SuppressLint; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; @@ -21,9 +22,6 @@ import org.meowcat.edxposed.manager.MainActivity; import org.meowcat.edxposed.manager.R; import org.meowcat.edxposed.manager.XposedApp; -import java.util.LinkedList; -import java.util.List; - public final class NotificationUtil { public static final int NOTIFICATION_MODULE_NOT_ACTIVATED_YET = 0; @@ -39,195 +37,188 @@ public final class NotificationUtil { private static final int PENDING_INTENT_ACTIVATE_MODULE = 5; private static final int PENDING_INTENT_INSTALL_APK = 6; - private static final String COLORED_NOTIFICATION = "colored_notification"; private static final String HEADS_UP = "heads_up"; private static final String FRAGMENT_ID = "fragment"; private static final String NOTIFICATION_UPDATE_CHANNEL = "app_update_channel"; private static final String NOTIFICATION_MODULES_CHANNEL = "modules_channel"; - private static Context sContext = null; - private static NotificationManager sNotificationManager; + @SuppressLint("StaticFieldLeak") + private static Context context = null; + private static NotificationManager notificationManager; private static SharedPreferences prefs; public static void init() { - if (sContext != null) return; + if (context != null) { + return; + } - sContext = XposedApp.getInstance(); + context = XposedApp.getInstance(); prefs = XposedApp.getPreferences(); - sNotificationManager = (NotificationManager) sContext.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel channel = new NotificationChannel(NOTIFICATION_UPDATE_CHANNEL, sContext.getString(R.string.download_section_update_available), NotificationManager.IMPORTANCE_DEFAULT); - NotificationChannel channel1 = new NotificationChannel(NOTIFICATION_MODULES_CHANNEL, sContext.getString(R.string.nav_item_modules), NotificationManager.IMPORTANCE_DEFAULT); - sNotificationManager.createNotificationChannel(channel); - sNotificationManager.createNotificationChannel(channel1); + NotificationChannel channelUpdate = new NotificationChannel(NOTIFICATION_UPDATE_CHANNEL, context.getString(R.string.download_section_update_available), NotificationManager.IMPORTANCE_DEFAULT); + NotificationChannel channelModule = new NotificationChannel(NOTIFICATION_MODULES_CHANNEL, context.getString(R.string.nav_item_modules), NotificationManager.IMPORTANCE_DEFAULT); + notificationManager.createNotificationChannel(channelUpdate); + notificationManager.createNotificationChannel(channelModule); } } public static void cancel(int id) { - sNotificationManager.cancel(id); + notificationManager.cancel(id); } public static void cancel(String tag, int id) { - sNotificationManager.cancel(tag, id); + notificationManager.cancel(tag, id); } public static void cancelAll() { - sNotificationManager.cancelAll(); + notificationManager.cancelAll(); } public static void showNotActivatedNotification(String packageName, String appName) { - Intent intent = new Intent(sContext, MainActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).putExtra(FRAGMENT_ID, 1); - PendingIntent pModulesTab = PendingIntent.getActivity(sContext, PENDING_INTENT_OPEN_MODULES, intent, PendingIntent.FLAG_UPDATE_CURRENT); + Intent intent = new Intent(context, MainActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).putExtra(FRAGMENT_ID, 1); + PendingIntent pModulesTab = PendingIntent.getActivity(context, PENDING_INTENT_OPEN_MODULES, intent, 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) - .setVibrate(new long[]{0}).setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification); - - if (prefs.getBoolean(HEADS_UP, true) && Build.VERSION.SDK_INT >= 21) + String title = context.getString(R.string.module_is_not_activated_yet); + NotificationCompat.Builder builder = getNotificationBuilder(title, appName, NOTIFICATION_MODULES_CHANNEL) + .setContentIntent(pModulesTab); + if (prefs.getBoolean(HEADS_UP, true)) { builder.setPriority(2); - builder.setColor(ContextCompat.getColor(sContext, R.color.colorPrimary)); - Intent iActivateAndReboot = new Intent(sContext, RebootReceiver.class); + } + Intent iActivateAndReboot = new Intent(context, RebootReceiver.class); iActivateAndReboot.putExtra(RebootReceiver.EXTRA_ACTIVATE_MODULE, packageName); - PendingIntent pActivateAndReboot = PendingIntent.getBroadcast(sContext, PENDING_INTENT_ACTIVATE_MODULE_AND_REBOOT, + PendingIntent pActivateAndReboot = PendingIntent.getBroadcast(context, PENDING_INTENT_ACTIVATE_MODULE_AND_REBOOT, iActivateAndReboot, PendingIntent.FLAG_UPDATE_CURRENT); - - Intent iActivate = new Intent(sContext, RebootReceiver.class); + Intent iActivate = new Intent(context, RebootReceiver.class); iActivate.putExtra(RebootReceiver.EXTRA_ACTIVATE_MODULE, packageName); iActivate.putExtra(RebootReceiver.EXTRA_ACTIVATE_MODULE_AND_RETURN, true); - PendingIntent pActivate = PendingIntent.getBroadcast(sContext, PENDING_INTENT_ACTIVATE_MODULE, + PendingIntent pActivate = PendingIntent.getBroadcast(context, PENDING_INTENT_ACTIVATE_MODULE, iActivate, 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)); - builder.setStyle(notiStyle).setChannelId(NOTIFICATION_MODULES_CHANNEL); + NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle(); + style.setBigContentTitle(title); + style.bigText(context.getString(R.string.module_is_not_activated_yet_detailed, appName)); + builder.setStyle(style); // 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(new NotificationCompat.Action.Builder(R.drawable.ic_apps, sContext.getString(R.string.activate_and_reboot), pActivateAndReboot).build()); - builder.addAction(new NotificationCompat.Action.Builder(R.drawable.ic_apps, sContext.getString(R.string.activate_only), pActivate).build()); + builder.addAction(new NotificationCompat.Action.Builder(R.drawable.ic_apps, context.getString(R.string.activate_and_reboot), pActivateAndReboot).build()); + builder.addAction(new NotificationCompat.Action.Builder(R.drawable.ic_apps, context.getString(R.string.activate_only), pActivate).build()); } - sNotificationManager.notify(packageName, NOTIFICATION_MODULE_NOT_ACTIVATED_YET, builder.build()); + notificationManager.notify(packageName, NOTIFICATION_MODULE_NOT_ACTIVATED_YET, builder.build()); } public static void showModulesUpdatedNotification() { - Intent intent = new Intent(sContext, MainActivity.class); + Intent intent = new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(FRAGMENT_ID, 0); - PendingIntent pInstallTab = PendingIntent.getActivity(sContext, PENDING_INTENT_OPEN_INSTALL, + PendingIntent pInstallTab = PendingIntent.getActivity(context, PENDING_INTENT_OPEN_INSTALL, intent, PendingIntent.FLAG_UPDATE_CURRENT); - String title = sContext + String title = context .getString(R.string.xposed_module_updated_notification_title); - String message = sContext + String message = context .getString(R.string.xposed_module_updated_notification); - NotificationCompat.Builder builder = new NotificationCompat.Builder(sContext).setContentTitle(title).setContentText(message) - .setTicker(title).setContentIntent(pInstallTab) - .setVibrate(new long[]{0}).setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification); - - if (prefs.getBoolean(HEADS_UP, true) && Build.VERSION.SDK_INT >= 21) + NotificationCompat.Builder builder = getNotificationBuilder(title, message, NOTIFICATION_MODULES_CHANNEL) + .setContentIntent(pInstallTab); + if (prefs.getBoolean(HEADS_UP, true)) { builder.setPriority(2); - builder.setColor(ContextCompat.getColor(sContext, R.color.colorPrimary)); - Intent iSoftReboot = new Intent(sContext, RebootReceiver.class); + } + Intent iSoftReboot = new Intent(context, RebootReceiver.class); iSoftReboot.putExtra(RebootReceiver.EXTRA_SOFT_REBOOT, true); - PendingIntent pSoftReboot = PendingIntent.getBroadcast(sContext, PENDING_INTENT_SOFT_REBOOT, + PendingIntent pSoftReboot = PendingIntent.getBroadcast(context, PENDING_INTENT_SOFT_REBOOT, iSoftReboot, PendingIntent.FLAG_UPDATE_CURRENT); - Intent iReboot = new Intent(sContext, RebootReceiver.class); - PendingIntent pReboot = PendingIntent.getBroadcast(sContext, PENDING_INTENT_REBOOT, + Intent iReboot = new Intent(context, RebootReceiver.class); + PendingIntent pReboot = PendingIntent.getBroadcast(context, PENDING_INTENT_REBOOT, iReboot, PendingIntent.FLAG_UPDATE_CURRENT); - builder.addAction(new NotificationCompat.Action.Builder(0, sContext.getString(R.string.reboot), pReboot).build()); - builder.addAction(new NotificationCompat.Action.Builder(0, sContext.getString(R.string.soft_reboot), pSoftReboot).build()); - builder.setChannelId(NOTIFICATION_MODULES_CHANNEL); + builder.addAction(new NotificationCompat.Action.Builder(0, context.getString(R.string.reboot), pReboot).build()); + builder.addAction(new NotificationCompat.Action.Builder(0, context.getString(R.string.soft_reboot), pSoftReboot).build()); - sNotificationManager.notify(null, NOTIFICATION_MODULES_UPDATED, builder.build()); + notificationManager.notify(null, NOTIFICATION_MODULES_UPDATED, builder.build()); } static void showModuleInstallNotification(@StringRes int title, @StringRes int message, String path, Object... args) { - showModuleInstallNotification(sContext.getString(title), sContext.getString(message, args), path, title == R.string.installation_error); + showModuleInstallNotification(context.getString(title), context.getString(message, args), path, title == R.string.installation_error); } private static void showModuleInstallNotification(String title, String message, String path, boolean error) { - NotificationCompat.Builder builder = new NotificationCompat.Builder( - sContext).setContentTitle(title).setContentText(message) - .setVibrate(new long[]{0}).setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification); + NotificationCompat.Builder builder = getNotificationBuilder(title, message, NOTIFICATION_MODULES_CHANNEL); if (error) { - Intent iInstallApk = new Intent(sContext, ApkReceiver.class); + Intent iInstallApk = new Intent(context, ApkReceiver.class); iInstallApk.putExtra(ApkReceiver.EXTRA_APK_PATH, path); - PendingIntent pInstallApk = PendingIntent.getBroadcast(sContext, PENDING_INTENT_INSTALL_APK, iInstallApk, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pInstallApk = PendingIntent.getBroadcast(context, PENDING_INTENT_INSTALL_APK, iInstallApk, PendingIntent.FLAG_UPDATE_CURRENT); - builder.addAction(new NotificationCompat.Action.Builder(0, sContext.getString(R.string.installation_apk_normal), pInstallApk).build()); + builder.addAction(new NotificationCompat.Action.Builder(0, context.getString(R.string.installation_apk_normal), pInstallApk).build()); } - if (prefs.getBoolean(HEADS_UP, true) && Build.VERSION.SDK_INT >= 21) + if (prefs.getBoolean(HEADS_UP, true)) { builder.setPriority(2); - builder.setColor(ContextCompat.getColor(sContext, R.color.colorPrimary)); + } NotificationCompat.BigTextStyle notiStyle = new NotificationCompat.BigTextStyle(); notiStyle.setBigContentTitle(title); notiStyle.bigText(message); - builder.setStyle(notiStyle).setChannelId(NOTIFICATION_MODULES_CHANNEL); + builder.setStyle(notiStyle); - sNotificationManager.notify(null, NOTIFICATION_MODULE_INSTALLATION, builder.build()); + notificationManager.notify(null, NOTIFICATION_MODULE_INSTALLATION, builder.build()); - new android.os.Handler().postDelayed(new Runnable() { - @Override - public void run() { - cancel(NOTIFICATION_MODULE_INSTALLATION); - } - }, 10 * 1000); + new android.os.Handler().postDelayed(() -> cancel(NOTIFICATION_MODULE_INSTALLATION), 10 * 1000); } public static void showModuleInstallingNotification(String appName) { - String title = sContext.getString(R.string.install_load); - String message = sContext.getString(R.string.install_load_apk, appName); - NotificationCompat.Builder builder = new NotificationCompat.Builder(sContext).setContentTitle(title).setContentText(message) - .setVibrate(new long[]{0}).setProgress(0, 0, true) - .setSmallIcon(R.drawable.ic_notification).setOngoing(true); - builder.setColor(ContextCompat.getColor(sContext, R.color.colorPrimary)); + String title = context.getString(R.string.install_load); + String message = context.getString(R.string.install_load_apk, appName); + NotificationCompat.Builder builder = getNotificationBuilder(title, message, NOTIFICATION_MODULES_CHANNEL) + .setProgress(0, 0, true) + .setOngoing(true); NotificationCompat.BigTextStyle notiStyle = new NotificationCompat.BigTextStyle(); notiStyle.setBigContentTitle(title); notiStyle.bigText(message); - builder.setStyle(notiStyle).setChannelId(NOTIFICATION_MODULES_CHANNEL); + builder.setStyle(notiStyle); - sNotificationManager.notify(null, NOTIFICATION_MODULE_INSTALLING, builder.build()); + notificationManager.notify(null, NOTIFICATION_MODULE_INSTALLING, builder.build()); } public static void showInstallerUpdateNotification() { - Intent intent = new Intent(sContext, MainActivity.class); + Intent intent = new Intent(context, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(FRAGMENT_ID, 0); - PendingIntent pInstallTab = PendingIntent.getActivity(sContext, PENDING_INTENT_OPEN_INSTALL, + PendingIntent pInstallTab = PendingIntent.getActivity(context, PENDING_INTENT_OPEN_INSTALL, intent, PendingIntent.FLAG_UPDATE_CURRENT); - String title = sContext.getString(R.string.app_name); - String message = sContext.getString(R.string.newVersion); - NotificationCompat.Builder builder = new NotificationCompat.Builder(sContext).setContentTitle(title).setContentText(message) - .setTicker(title).setContentIntent(pInstallTab) - .setVibrate(new long[]{0}).setAutoCancel(true) - .setSmallIcon(R.drawable.ic_notification); + String title = context.getString(R.string.app_name); + String message = context.getString(R.string.newVersion); + NotificationCompat.Builder builder = getNotificationBuilder(title, message, NOTIFICATION_UPDATE_CHANNEL) + .setContentIntent(pInstallTab); - if (prefs.getBoolean(HEADS_UP, true) && Build.VERSION.SDK_INT >= 21) + if (prefs.getBoolean(HEADS_UP, true)) { builder.setPriority(2); - builder.setColor(ContextCompat.getColor(sContext, R.color.colorPrimary)); + } NotificationCompat.BigTextStyle notiStyle = new NotificationCompat.BigTextStyle(); notiStyle.setBigContentTitle(title); notiStyle.bigText(message); - builder.setStyle(notiStyle).setChannelId(NOTIFICATION_UPDATE_CHANNEL); + builder.setStyle(notiStyle); - sNotificationManager.notify(null, NOTIFICATION_INSTALLER_UPDATE, builder.build()); + notificationManager.notify(null, NOTIFICATION_INSTALLER_UPDATE, builder.build()); + } + + private static NotificationCompat.Builder getNotificationBuilder(String title, String message, String channel) { + return new NotificationCompat.Builder(context, channel) + .setContentTitle(title) + .setContentText(message) + .setVibrate(new long[]{0}) + .setAutoCancel(true) + .setSmallIcon(R.drawable.ic_notification) + .setColor(ContextCompat.getColor(context, R.color.colorPrimary)); } public static class RebootReceiver extends BroadcastReceiver { @@ -244,7 +235,7 @@ public final class NotificationUtil { * expanded notification panel and is therefore not visible to the * user. */ - sContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); cancelAll(); if (intent.hasExtra(EXTRA_ACTIVATE_MODULE)) { @@ -252,7 +243,7 @@ public final class NotificationUtil { ModuleUtil moduleUtil = ModuleUtil.getInstance(); moduleUtil.setModuleEnabled(packageName, true); moduleUtil.updateModulesList(false); - Toast.makeText(sContext, R.string.module_activated, Toast.LENGTH_SHORT).show(); + Toast.makeText(context, R.string.module_activated, Toast.LENGTH_SHORT).show(); if (intent.hasExtra(EXTRA_ACTIVATE_MODULE_AND_RETURN)) return; } @@ -262,7 +253,6 @@ public final class NotificationUtil { return; } - List messages = new LinkedList<>(); boolean isSoftReboot = intent.getBooleanExtra(EXTRA_SOFT_REBOOT, false); int returnCode = isSoftReboot @@ -287,7 +277,7 @@ public final class NotificationUtil { * expanded notification panel and is therefore not visible to the * user. */ - sContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); if (intent.hasExtra(EXTRA_APK_PATH)) { String path = intent.getStringExtra(EXTRA_APK_PATH); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/util/RepoLoader.java b/app/src/main/java/org/meowcat/edxposed/manager/util/RepoLoader.java index 4ac0f66f..5d562576 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/util/RepoLoader.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/util/RepoLoader.java @@ -46,48 +46,48 @@ import java.util.zip.GZIPInputStream; public class RepoLoader { private static final int UPDATE_FREQUENCY = 24 * 60 * 60 * 1000; private static String DEFAULT_REPOSITORIES; - private static RepoLoader mInstance = null; - private final List mListeners = new CopyOnWriteArrayList<>(); - private final Map mLocalReleaseTypesCache = new HashMap<>(); - private XposedApp mApp; - private SharedPreferences mPref; - private SharedPreferences mModulePref; - private ConnectivityManager mConMgr; - private boolean mIsLoading = false; - private boolean mReloadTriggeredOnce = false; - private Map mRepositories = null; - private ReleaseType mGlobalReleaseType; - private SwipeRefreshLayout mSwipeRefreshLayout; + private static RepoLoader instance = null; + private final List listeners = new CopyOnWriteArrayList<>(); + private final Map localReleaseTypesCache = new HashMap<>(); + private XposedApp app; + private SharedPreferences pref; + private SharedPreferences modulePref; + private ConnectivityManager conMgr; + private boolean isLoading = false; + private boolean reloadTriggeredOnce = false; + private Map repositories = null; + private ReleaseType globalReleaseType; + private SwipeRefreshLayout swipeRefreshLayout; private RepoLoader() { - mInstance = this; - mApp = XposedApp.getInstance(); - mPref = mApp.getSharedPreferences("repo", Context.MODE_PRIVATE); + instance = this; + app = XposedApp.getInstance(); + pref = app.getSharedPreferences("repo", Context.MODE_PRIVATE); DEFAULT_REPOSITORIES = XposedApp.getPreferences().getBoolean("custom_list", false) ? "https://cdn.jsdelivr.net/gh/ElderDrivers/Repository-Website@gh-pages/assets/full.xml.gz" : "https://dl-xda.xposed.info/repo/full.xml.gz"; - 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")); + modulePref = app.getSharedPreferences("module_settings", Context.MODE_PRIVATE); + conMgr = (ConnectivityManager) app.getSystemService(Context.CONNECTIVITY_SERVICE); + globalReleaseType = ReleaseType.fromString(XposedApp.getPreferences().getString("release_type_global", "stable")); refreshRepositories(); } public static synchronized RepoLoader getInstance() { - if (mInstance == null) + if (instance == null) new RepoLoader(); - return mInstance; + return instance; } private boolean refreshRepositories() { - mRepositories = RepoDb.getRepositories(); + repositories = RepoDb.getRepositories(); // 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("\\|"); - if (mRepositories.size() != config.length) { + String[] config = (pref.getString("repositories", DEFAULT_REPOSITORIES) + "").split("\\|"); + if (repositories.size() != config.length) { needReload = true; } else { int i = 0; - for (Repository repo : mRepositories.values()) { + for (Repository repo : repositories.values()) { if (!repo.url.equals(config[i++])) { needReload = true; break; @@ -102,16 +102,16 @@ public class RepoLoader { for (String url : config) { RepoDb.insertRepository(url); } - mRepositories = RepoDb.getRepositories(); + repositories = RepoDb.getRepositories(); return true; } public void setReleaseTypeGlobal(String relTypeString) { ReleaseType relType = ReleaseType.fromString(relTypeString); - if (mGlobalReleaseType == relType) + if (globalReleaseType == relType) return; - mGlobalReleaseType = relType; + globalReleaseType = relType; // Updating the latest version for all modules takes a moment new Thread("DBUpdate") { @@ -129,8 +129,10 @@ public class RepoLoader { if (getReleaseTypeLocal(packageName) == relType) return; - synchronized (mLocalReleaseTypesCache) { - mLocalReleaseTypesCache.put(packageName, relType); + synchronized (localReleaseTypesCache) { + if (relType != null) { + localReleaseTypesCache.put(packageName, relType); + } } RepoDb.updateModuleLatestVersion(packageName); @@ -138,20 +140,22 @@ public class RepoLoader { } private ReleaseType getReleaseTypeLocal(String packageName) { - synchronized (mLocalReleaseTypesCache) { - if (mLocalReleaseTypesCache.containsKey(packageName)) - return mLocalReleaseTypesCache.get(packageName); + synchronized (localReleaseTypesCache) { + if (localReleaseTypesCache.containsKey(packageName)) + return localReleaseTypesCache.get(packageName); - String value = mModulePref.getString(packageName + "_release_type", + String value = modulePref.getString(packageName + "_release_type", null); ReleaseType result = (!TextUtils.isEmpty(value)) ? ReleaseType.fromString(value) : null; - mLocalReleaseTypesCache.put(packageName, result); + if (result != null) { + localReleaseTypesCache.put(packageName, result); + } return result; } } public Repository getRepository(long repoId) { - return mRepositories.get(repoId); + return repositories.get(repoId); } public Module getModule(String packageName) { @@ -179,42 +183,42 @@ public class RepoLoader { if (localSetting != null) return localSetting; else - return mGlobalReleaseType; + return globalReleaseType; } public void triggerReload(final boolean force) { - mReloadTriggeredOnce = true; + reloadTriggeredOnce = true; if (force) { resetLastUpdateCheck(); } else { - long lastUpdateCheck = mPref.getLong("last_update_check", 0); + long lastUpdateCheck = pref.getLong("last_update_check", 0); if (System.currentTimeMillis() < lastUpdateCheck + UPDATE_FREQUENCY) return; } - NetworkInfo netInfo = mConMgr.getActiveNetworkInfo(); + NetworkInfo netInfo = conMgr.getActiveNetworkInfo(); if (netInfo == null || !netInfo.isConnected()) return; synchronized (this) { - if (mIsLoading) + if (isLoading) return; - mIsLoading = true; + isLoading = true; } - mApp.updateProgressIndicator(mSwipeRefreshLayout); + app.updateProgressIndicator(swipeRefreshLayout); new Thread("RepositoryReload") { public void run() { final List messages = new LinkedList<>(); boolean hasChanged = downloadAndParseFiles(messages); - mPref.edit().putLong("last_update_check", System.currentTimeMillis()).apply(); + pref.edit().putLong("last_update_check", System.currentTimeMillis()).apply(); if (!messages.isEmpty()) { XposedApp.runOnUiThread(() -> { for (String message : messages) { - Toast.makeText(mApp, message, Toast.LENGTH_LONG).show(); + Toast.makeText(app, message, Toast.LENGTH_LONG).show(); } }); } @@ -223,38 +227,38 @@ public class RepoLoader { notifyListeners(); synchronized (this) { - mIsLoading = false; + isLoading = false; } - mApp.updateProgressIndicator(mSwipeRefreshLayout); + app.updateProgressIndicator(swipeRefreshLayout); } }.start(); } - public void setSwipeRefreshLayout(SwipeRefreshLayout mSwipeRefreshLayout) { - this.mSwipeRefreshLayout = mSwipeRefreshLayout; + public void setSwipeRefreshLayout(SwipeRefreshLayout swipeRefreshLayout) { + this.swipeRefreshLayout = swipeRefreshLayout; } public void triggerFirstLoadIfNecessary() { - if (!mReloadTriggeredOnce) + if (!reloadTriggeredOnce) triggerReload(false); } public void resetLastUpdateCheck() { - mPref.edit().remove("last_update_check").apply(); + pref.edit().remove("last_update_check").apply(); } public synchronized boolean isLoading() { - return mIsLoading; + return isLoading; } public void clear(boolean notify) { synchronized (this) { // TODO Stop reloading repository when it should be cleared - if (mIsLoading) + if (isLoading) return; RepoDb.deleteRepositories(); - mRepositories = new LinkedHashMap<>(0); + repositories = new LinkedHashMap<>(0); DownloadsUtil.clearCache(null); resetLastUpdateCheck(); } @@ -270,7 +274,7 @@ public class RepoLoader { sb.append("|"); sb.append(repos[i]); } - mPref.edit().putString("repositories", sb.toString()).apply(); + pref.edit().putString("repositories", sb.toString()).apply(); if (refreshRepositories()) triggerReload(true); } @@ -287,7 +291,7 @@ public class RepoLoader { String filename = "repo_" + HashUtil.md5(repo) + ".xml"; if (repo.endsWith(".gz")) filename += ".gz"; - return new File(mApp.getCacheDir(), filename); + return new File(app.getCacheDir(), filename); } private boolean downloadAndParseFiles(List messages) { @@ -296,7 +300,7 @@ public class RepoLoader { final AtomicInteger insertCounter = new AtomicInteger(); final AtomicInteger deleteCounter = new AtomicInteger(); - for (Entry repoEntry : mRepositories.entrySet()) { + for (Entry repoEntry : repositories.entrySet()) { final long repoId = repoEntry.getKey(); final Repository repo = repoEntry.getValue(); @@ -367,13 +371,13 @@ public class RepoLoader { RepoDb.setTransactionSuccessful(); } catch (SQLiteException e) { - XposedApp.runOnUiThread(() -> new MaterialAlertDialogBuilder(mApp) + XposedApp.runOnUiThread(() -> new MaterialAlertDialogBuilder(app) .setTitle(R.string.restart_needed) .setMessage(R.string.cache_cleaned) .setPositiveButton(android.R.string.ok, (dialog, which) -> { - Intent i = new Intent(mApp, DownloadActivity.class); - PendingIntent pi = PendingIntent.getActivity(mApp, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); - AlarmManager mgr = (AlarmManager) mApp.getSystemService(Context.ALARM_SERVICE); + Intent i = new Intent(app, DownloadActivity.class); + PendingIntent pi = PendingIntent.getActivity(app, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); + AlarmManager mgr = (AlarmManager) app.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pi); System.exit(0); }) @@ -383,7 +387,7 @@ public class RepoLoader { DownloadsUtil.clearCache(url); } catch (Throwable t) { Log.e(XposedApp.TAG, "RepoLoader -> Cannot load repository from " + url, t); - messages.add(mApp.getString(R.string.repo_load_failed, url, t.getMessage())); + messages.add(app.getString(R.string.repo_load_failed, url, t.getMessage())); DownloadsUtil.clearCache(url); } finally { if (in != null) @@ -391,6 +395,7 @@ public class RepoLoader { in.close(); } catch (IOException ignored) { } + //noinspection ResultOfMethodCallIgnored cacheFile.delete(); RepoDb.endTransation(); } @@ -402,20 +407,20 @@ public class RepoLoader { } public void addListener(RepoListener listener, boolean triggerImmediately) { - if (!mListeners.contains(listener)) - mListeners.add(listener); + if (!listeners.contains(listener)) + listeners.add(listener); if (triggerImmediately) listener.onRepoReloaded(this); } public void removeListener(RepoListener listener) { - mListeners.remove(listener); + listeners.remove(listener); } private void notifyListeners() { - for (RepoListener listener : mListeners) { - listener.onRepoReloaded(mInstance); + for (RepoListener listener : listeners) { + listener.onRepoReloaded(instance); } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0c5087d0..7a99c25d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,308 +1,327 @@ - + android:clipChildren="false" + android:clipToPadding="false"> - - - - - - - - - - - + android:layout_height="match_parent" + android:animateLayoutChanges="true" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="vertical" + tools:context=".MainActivity"> - + - + + + + + + + + android:layout_marginHorizontal="16dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="#4CAF50" + app:cardCornerRadius="8dp" + app:cardElevation="8dp"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + android:background="@drawable/main_item_background" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + android:padding="16dp"> - + - + + - - - + android:layout_marginHorizontal="16dp" + android:layout_marginTop="5dp" + android:background="@drawable/main_item_background" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + android:padding="16dp"> - + + + + + - - + android:layout_marginHorizontal="16dp" + android:layout_marginTop="5dp" + android:background="@drawable/main_item_background" + android:clickable="true" + android:focusable="true" + android:orientation="horizontal" + android:padding="16dp"> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_module.xml b/app/src/main/res/layout/item_module.xml index ed43fd86..b68ac362 100644 --- a/app/src/main/res/layout/item_module.xml +++ b/app/src/main/res/layout/item_module.xml @@ -1,114 +1,113 @@ - + android:focusable="true" + android:minHeight="?attr/listPreferredItemHeight" + android:padding="8dp"> - + + + android:layout_marginStart="8dp" + android:singleLine="false" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textIsSelectable="false" + app:layout_constraintStart_toEndOf="@id/app_icon" + app:layout_constraintTop_toTopOf="parent" + tools:text="@tools:sample/first_names" /> - + - + - + - + - + - + - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file