View binding

This commit is contained in:
NekoInverter 2020-03-06 20:53:56 +08:00
parent f61aadf509
commit 4ee0d48af6
No known key found for this signature in database
GPG Key ID: 280D6CCCF95715F9
40 changed files with 1087 additions and 1316 deletions

View File

@ -2,6 +2,9 @@ apply plugin: 'com.android.application'
apply plugin: 'com.google.android.gms.oss-licenses-plugin'
android {
viewBinding {
enabled = true
}
compileSdkVersion 28
buildToolsVersion "29.0.3"
defaultConfig {

View File

@ -6,41 +6,30 @@ import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.Html;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.meowcat.edxposed.manager.databinding.ActivityAboutBinding;
import org.meowcat.edxposed.manager.util.NavUtil;
public class AboutActivity extends BaseActivity {
ActivityAboutBinding binding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityAboutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appbar.toolbar);
binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
View changelogView = findViewById(R.id.changelogView);
View licensesView = findViewById(R.id.licensesView);
View translatorsView = findViewById(R.id.translatorsView);
View sourceCodeView = findViewById(R.id.sourceCodeView);
View tgChannelView = findViewById(R.id.tgChannelView);
View installerSupportView = findViewById(R.id.installerSupportView);
View faqView = findViewById(R.id.faqView);
View donateView = findViewById(R.id.donateView);
TextView txtModuleSupport = findViewById(R.id.tab_support_module_description);
View qqGroupView = findViewById(R.id.qqGroupView);
View tgGroupView = findViewById(R.id.tgGroupView);
setupWindowInsets(binding.snackbar, binding.nestedScrollView);
String packageName = getPackageName();
String translator = getResources().getString(R.string.translator);
@ -50,9 +39,9 @@ public class AboutActivity extends BaseActivity {
final String changes = prefs.getString("changelog", null);
if (changes == null) {
changelogView.setVisibility(View.GONE);
binding.changelogView.setVisibility(View.GONE);
} else {
changelogView.setOnClickListener(v1 -> new MaterialAlertDialogBuilder(this)
binding.changelogView.setOnClickListener(v1 -> new MaterialAlertDialogBuilder(this)
.setTitle(R.string.changes)
.setMessage(Html.fromHtml(changes))
.setPositiveButton(android.R.string.ok, null).show());
@ -60,25 +49,25 @@ public class AboutActivity extends BaseActivity {
try {
String version = getPackageManager().getPackageInfo(packageName, 0).versionName;
((TextView) findViewById(R.id.app_version)).setText(version);
binding.appVersion.setText(version);
} catch (PackageManager.NameNotFoundException ignored) {
}
licensesView.setOnClickListener(v12 -> startActivity(new Intent(this, OssLicensesMenuActivity.class)));
binding.licensesView.setOnClickListener(v12 -> startActivity(new Intent(this, OssLicensesMenuActivity.class)));
txtModuleSupport.setText(getString(R.string.support_modules_description,
binding.tabSupportModuleDescription.setText(getString(R.string.support_modules_description,
getString(R.string.module_support)));
setupView(installerSupportView, R.string.support_material_xda);
setupView(faqView, R.string.support_faq_url);
setupView(tgGroupView, R.string.group_telegram_link);
setupView(qqGroupView, R.string.group_qq_link);
setupView(donateView, R.string.support_donate_url);
setupView(sourceCodeView, R.string.about_source);
setupView(tgChannelView, R.string.group_telegram_channel_link);
setupView(binding.installerSupportView, R.string.support_material_xda);
setupView(binding.faqView, R.string.support_faq_url);
setupView(binding.tgGroupView, R.string.group_telegram_link);
setupView(binding.qqGroupView, R.string.group_qq_link);
setupView(binding.donateView, R.string.support_donate_url);
setupView(binding.sourceCodeView, R.string.about_source);
setupView(binding.tgChannelView, R.string.group_telegram_channel_link);
if (translator.isEmpty()) {
translatorsView.setVisibility(View.GONE);
binding.translatorsView.setVisibility(View.GONE);
}
}
@ -86,8 +75,4 @@ public class AboutActivity extends BaseActivity {
v.setOnClickListener(v1 -> NavUtil.startURL(this, getString(url)));
}
public void openLink(View view) {
NavUtil.startURL(this, view.getTag().toString());
}
}

View File

@ -63,11 +63,13 @@ public class BaseActivity extends AppCompatActivity {
return (configuration.uiMode & Configuration.UI_MODE_NIGHT_YES) > 0;
}
protected void setupWindowInsets() {
View rootView = findViewById(R.id.snackbar);
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) -> {
rootView.setPadding(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
if (secondView != null) {
secondView.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
}
rootView.setPadding(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getTappableElementInsets().bottom);
return insets;
});
}

View File

@ -1,5 +1,6 @@
package org.meowcat.edxposed.manager;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
@ -8,10 +9,6 @@ import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -21,15 +18,15 @@ import androidx.fragment.app.Fragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.meowcat.edxposed.manager.databinding.SingleInstallerViewBinding;
import org.meowcat.edxposed.manager.util.NavUtil;
import org.meowcat.edxposed.manager.util.json.XposedTab;
import org.meowcat.edxposed.manager.util.json.XposedZip;
import java.util.List;
import java.util.Objects;
public class BaseAdvancedInstaller extends Fragment {
private View mClickedButton;
SingleInstallerViewBinding binding;
static BaseAdvancedInstaller newInstance(XposedTab tab) {
BaseAdvancedInstaller myFragment = new BaseAdvancedInstaller();
@ -41,75 +38,33 @@ public class BaseAdvancedInstaller extends Fragment {
return myFragment;
}
private List<XposedZip> installers() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).installers;
}
private List<XposedZip> uninstallers() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).uninstallers;
}
private String notice() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).notice;
}
protected String author() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).author;
}
private String supportUrl() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).support;
}
protected boolean isStable() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).stable;
}
private boolean isOfficial() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).official;
}
private String description() {
XposedTab tab = Objects.requireNonNull(getArguments()).getParcelable("tab");
return Objects.requireNonNull(tab).description;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.single_installer_view, container, false);
final Spinner chooserInstallers = view.findViewById(R.id.chooserInstallers);
final Spinner chooserUninstallers = view.findViewById(R.id.chooserUninstallers);
final Button btnInstall = view.findViewById(R.id.btnInstall);
final Button btnUninstall = view.findViewById(R.id.btnUninstall);
ImageView infoInstaller = view.findViewById(R.id.infoInstaller);
ImageView infoUninstaller = view.findViewById(R.id.infoUninstaller);
TextView noticeTv = view.findViewById(R.id.noticeTv);
TextView author = view.findViewById(R.id.author);
View showOnXda = view.findViewById(R.id.show_on_xda);
View updateDescription = view.findViewById(R.id.updateDescription);
TooltipCompat.setTooltipText(infoInstaller, getString(R.string.info));
TooltipCompat.setTooltipText(infoUninstaller, getString(R.string.info));
Bundle arguments = getArguments();
if (arguments == null) {
return null;
} else if (arguments.getParcelable("tab") == null) {
return null;
}
XposedTab tab = arguments.getParcelable("tab");
if (tab == null) {
return null;
}
binding = SingleInstallerViewBinding.inflate(inflater, container, false);
TooltipCompat.setTooltipText(binding.infoInstaller, getString(R.string.info));
TooltipCompat.setTooltipText(binding.infoUninstaller, getString(R.string.info));
try {
chooserInstallers.setAdapter(new XposedZip.MyAdapter(getContext(), installers()));
chooserUninstallers.setAdapter(new XposedZip.MyAdapter(getContext(), uninstallers()));
binding.chooserInstallers.setAdapter(new XposedZip.MyAdapter(getContext(), tab.installers));
binding.chooserUninstallers.setAdapter(new XposedZip.MyAdapter(getContext(), tab.uninstallers));
} catch (Exception ignored) {
}
infoInstaller.setOnClickListener(v -> {
XposedZip selectedInstaller = (XposedZip) chooserInstallers.getSelectedItem();
binding.infoInstaller.setOnClickListener(v -> {
XposedZip selectedInstaller = (XposedZip) binding.chooserInstallers.getSelectedItem();
String s = getString(R.string.infoInstaller,
selectedInstaller.name,
selectedInstaller.version);
@ -117,8 +72,8 @@ public class BaseAdvancedInstaller extends Fragment {
new MaterialAlertDialogBuilder(Objects.requireNonNull(getContext())).setTitle(R.string.info)
.setMessage(s).setPositiveButton(android.R.string.ok, null).show();
});
infoUninstaller.setOnClickListener(v -> {
XposedZip selectedUninstaller = (XposedZip) chooserUninstallers.getSelectedItem();
binding.infoUninstaller.setOnClickListener(v -> {
XposedZip selectedUninstaller = (XposedZip) binding.chooserUninstallers.getSelectedItem();
String s = getString(R.string.infoUninstaller,
selectedUninstaller.name,
selectedUninstaller.version);
@ -127,59 +82,60 @@ public class BaseAdvancedInstaller extends Fragment {
.setMessage(s).setPositiveButton(android.R.string.ok, null).show();
});
btnInstall.setOnClickListener(v -> areYouSure(R.string.warningArchitecture,
binding.btnInstall.setOnClickListener(v -> warningArchitecture(
(dialog, which) -> {
XposedZip selectedInstaller = (XposedZip) chooserInstallers.getSelectedItem();
XposedZip selectedInstaller = (XposedZip) binding.chooserInstallers.getSelectedItem();
Uri uri = Uri.parse(selectedInstaller.link);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}));
btnUninstall.setOnClickListener(v -> areYouSure(R.string.warningArchitecture,
binding.btnUninstall.setOnClickListener(v -> warningArchitecture(
(dialog, which) -> {
XposedZip selectedUninstaller = (XposedZip) chooserUninstallers.getSelectedItem();
XposedZip selectedUninstaller = (XposedZip) binding.chooserUninstallers.getSelectedItem();
Uri uri = Uri.parse(selectedUninstaller.link);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}));
noticeTv.setText(Html.fromHtml(notice()));
author.setText(getString(R.string.download_author, author()));
binding.noticeTv.setText(Html.fromHtml(tab.notice));
binding.author.setText(getString(R.string.download_author, tab.author));
try {
if (uninstallers().size() == 0) {
infoUninstaller.setVisibility(View.GONE);
chooserUninstallers.setVisibility(View.GONE);
btnUninstall.setVisibility(View.GONE);
if (tab.uninstallers.size() == 0) {
binding.infoUninstaller.setVisibility(View.GONE);
binding.chooserUninstallers.setVisibility(View.GONE);
binding.btnUninstall.setVisibility(View.GONE);
}
} catch (Exception ignored) {
}
if (!isStable()) {
view.findViewById(R.id.warning_unstable).setVisibility(View.VISIBLE);
if (!tab.stable) {
binding.warningUnstable.setVisibility(View.VISIBLE);
}
if (!isOfficial()) {
view.findViewById(R.id.warning_unofficial).setVisibility(View.VISIBLE);
if (!tab.official) {
binding.warningUnofficial.setVisibility(View.VISIBLE);
}
showOnXda.setOnClickListener(v -> NavUtil.startURL((AppCompatActivity) getActivity(), supportUrl()));
updateDescription.setOnClickListener(v -> new MaterialAlertDialogBuilder(Objects.requireNonNull(getContext()))
binding.showOnXda.setOnClickListener(v -> NavUtil.startURL((AppCompatActivity) getActivity(), tab.support));
binding.updateDescription.setOnClickListener(v -> new MaterialAlertDialogBuilder(Objects.requireNonNull(getContext()))
.setTitle(R.string.changes)
.setMessage(Html.fromHtml(description()))
.setMessage(Html.fromHtml(tab.description))
.setPositiveButton(android.R.string.ok, null).show());
return view;
return binding.getRoot();
}
@SuppressWarnings("SameParameterValue")
private void areYouSure(int contentTextId, DialogInterface.OnClickListener listener) {
new MaterialAlertDialogBuilder(Objects.requireNonNull(getActivity())).setTitle(R.string.areyousure)
.setMessage(contentTextId)
.setPositiveButton(android.R.string.yes, listener)
.setNegativeButton(android.R.string.no, null)
.show();
private void warningArchitecture(DialogInterface.OnClickListener listener) {
Activity activity = getActivity();
if (activity != null) {
new MaterialAlertDialogBuilder(activity)
.setTitle(R.string.areyousure)
.setMessage(R.string.warningArchitecture)
.setPositiveButton(android.R.string.yes, listener)
.setNegativeButton(android.R.string.no, null)
.show();
}
}
}

View File

@ -10,60 +10,56 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
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.BlackListAdapter;
import org.meowcat.edxposed.manager.adapters.CompatListAdapter;
import org.meowcat.edxposed.manager.databinding.ActivityBlackListBinding;
public class BlackListActivity extends BaseActivity implements AppAdapter.Callback {
private SwipeRefreshLayout mSwipeRefreshLayout;
private SearchView mSearchView;
private BlackListAdapter mAppAdapter;
private SearchView searchView;
private CompatListAdapter appAdapter;
private SearchView.OnQueryTextListener mSearchListener;
private SearchView.OnQueryTextListener searchListener;
private ActivityBlackListBinding binding;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_black_list);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityBlackListBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appbar.toolbar);
binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
RecyclerView mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
final boolean isWhiteListMode = isWhiteListMode();
mAppAdapter = new BlackListAdapter(this, isWhiteListMode);
mRecyclerView.setAdapter(mAppAdapter);
mAppAdapter.setCallback(this);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
setupWindowInsets(binding.snackbar, binding.recyclerView);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
appAdapter = new CompatListAdapter(this);
binding.recyclerView.setAdapter(appAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this,
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(mAppAdapter::refresh);
mSearchListener = new SearchView.OnQueryTextListener() {
binding.recyclerView.addItemDecoration(dividerItemDecoration);
appAdapter.setCallback(this);
binding.swipeRefreshLayout.setRefreshing(true);
binding.swipeRefreshLayout.setOnRefreshListener(appAdapter::refresh);
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
mAppAdapter.filter(query);
appAdapter.filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
mAppAdapter.filter(newText);
appAdapter.filter(newText);
return false;
}
};
@ -72,8 +68,8 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
getMenuInflater().inflate(R.menu.menu_app_list, menu);
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
mSearchView.setOnQueryTextListener(mSearchListener);
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setOnQueryTextListener(searchListener);
return super.onCreateOptionsMenu(menu);
}
@ -114,9 +110,9 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba
@Override
public void onDataReady() {
mSwipeRefreshLayout.setRefreshing(false);
String queryStr = mSearchView != null ? mSearchView.getQuery().toString() : "";
mAppAdapter.filter(queryStr);
binding.swipeRefreshLayout.setRefreshing(false);
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
appAdapter.filter(queryStr);
}
@Override
@ -127,10 +123,10 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba
@Override
public void onBackPressed() {
if (mSearchView.isIconified()) {
if (searchView.isIconified()) {
super.onBackPressed();
} else {
mSearchView.setIconified(true);
searchView.setIconified(true);
}
}
}

View File

@ -9,59 +9,55 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
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.databinding.ActivityBlackListBinding;
public class CompatListActivity extends BaseActivity implements AppAdapter.Callback {
private SwipeRefreshLayout mSwipeRefreshLayout;
private SearchView mSearchView;
private CompatListAdapter mAppAdapter;
private SearchView searchView;
private CompatListAdapter appAdapter;
private SearchView.OnQueryTextListener mSearchListener;
private SearchView.OnQueryTextListener searchListener;
private ActivityBlackListBinding binding;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_black_list);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityBlackListBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appbar.toolbar);
binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
RecyclerView mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAppAdapter = new CompatListAdapter(this);
mRecyclerView.setAdapter(mAppAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
setupWindowInsets(binding.snackbar, binding.recyclerView);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
appAdapter = new CompatListAdapter(this);
binding.recyclerView.setAdapter(appAdapter);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this,
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
mAppAdapter.setCallback(this);
binding.recyclerView.addItemDecoration(dividerItemDecoration);
appAdapter.setCallback(this);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(mAppAdapter::refresh);
binding.swipeRefreshLayout.setRefreshing(true);
binding.swipeRefreshLayout.setOnRefreshListener(appAdapter::refresh);
mSearchListener = new SearchView.OnQueryTextListener() {
searchListener = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
mAppAdapter.filter(query);
appAdapter.filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
mAppAdapter.filter(newText);
appAdapter.filter(newText);
return false;
}
};
@ -70,16 +66,16 @@ public class CompatListActivity extends BaseActivity implements AppAdapter.Callb
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
getMenuInflater().inflate(R.menu.menu_app_list, menu);
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
mSearchView.setOnQueryTextListener(mSearchListener);
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setOnQueryTextListener(searchListener);
return super.onCreateOptionsMenu(menu);
}
@Override
public void onDataReady() {
mSwipeRefreshLayout.setRefreshing(false);
String queryStr = mSearchView != null ? mSearchView.getQuery().toString() : "";
mAppAdapter.filter(queryStr);
binding.swipeRefreshLayout.setRefreshing(false);
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
appAdapter.filter(queryStr);
}
@Override
@ -90,10 +86,10 @@ public class CompatListActivity extends BaseActivity implements AppAdapter.Callb
@Override
public void onBackPressed() {
if (mSearchView.isIconified()) {
if (searchView.isIconified()) {
super.onBackPressed();
} else {
mSearchView.setIconified(true);
searchView.setIconified(true);
}
}

View File

@ -1,6 +1,5 @@
package org.meowcat.edxposed.manager;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@ -8,8 +7,6 @@ import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
@ -18,6 +15,7 @@ import androidx.appcompat.app.AppCompatDialogFragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.topjohnwu.superuser.Shell;
import org.meowcat.edxposed.manager.databinding.FragmentCompileDialogBinding;
import org.meowcat.edxposed.manager.util.ToastUtil;
import java.lang.ref.WeakReference;
@ -62,11 +60,9 @@ public class CompileDialogFragment extends AppCompatDialogFragment {
.setIcon(appInfo.loadIcon(pm))
.setTitle(appInfo.loadLabel(pm))
.setCancelable(false);
@SuppressLint("InflateParams") View customView = LayoutInflater.from(requireContext()).inflate(R.layout.fragment_compile_dialog, null);
builder.setView(customView);
TextView msgView = customView.findViewById(R.id.message);
//ProgressBar progressView = customView.findViewById(R.id.progress);
msgView.setText(msg);
FragmentCompileDialogBinding binding = FragmentCompileDialogBinding.inflate(LayoutInflater.from(requireContext()), null, false);
builder.setView(binding.getRoot());
binding.message.setText(msg);
AlertDialog alertDialog = builder.create();
alertDialog.setCanceledOnTouchOutside(false);
return alertDialog;

View File

@ -14,6 +14,8 @@ import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.snackbar.Snackbar;
import org.meowcat.edxposed.manager.databinding.ActivityCrashReportBinding;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -22,18 +24,20 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class CrashReportActivity extends AppCompatActivity {
ActivityCrashReportBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash_report);
findViewById(R.id.copyLogs).setOnClickListener(v -> {
binding = ActivityCrashReportBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.copyLogs.setOnClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
//Are there any devices without clipboard...?
if (clipboard != null) {
ClipData clip = ClipData.newPlainText("edcrash", getAllErrorDetailsFromIntent(getIntent()));
clipboard.setPrimaryClip(clip);
Snackbar.make(findViewById(R.id.snackbar), R.string.copy_toast_msg, Snackbar.LENGTH_SHORT).show();
Snackbar.make(binding.snackbar, R.string.copy_toast_msg, Snackbar.LENGTH_SHORT).show();
}
});

View File

@ -22,17 +22,17 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersAdapter;
import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersDecoration;
import org.meowcat.edxposed.manager.adapters.CursorRecyclerViewAdapter;
import org.meowcat.edxposed.manager.databinding.ActivityDownloadBinding;
import org.meowcat.edxposed.manager.databinding.ItemDownloadBinding;
import org.meowcat.edxposed.manager.repo.RepoDb;
import org.meowcat.edxposed.manager.repo.RepoDbDefinitions;
import org.meowcat.edxposed.manager.util.ModuleUtil;
@ -42,79 +42,73 @@ import java.text.DateFormat;
import java.util.Date;
public class DownloadActivity extends BaseActivity implements RepoLoader.RepoListener, ModuleUtil.ModuleListener, SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences mPref;
private DownloadsAdapter mAdapter;
private String mFilterText;
private RepoLoader mRepoLoader;
private ModuleUtil mModuleUtil;
private int mSortingOrder;
private SearchView mSearchView;
private SharedPreferences mIgnoredUpdatesPref;
private DownloadsAdapter adapter;
private String filterText;
private RepoLoader repoLoader;
private ModuleUtil moduleUtil;
private int sortingOrder;
private SearchView searchView;
private SharedPreferences ignoredUpdatesPref;
private boolean changed = false;
private BroadcastReceiver connectionListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mRepoLoader != null) {
mRepoLoader.triggerReload(true);
if (repoLoader != null) {
repoLoader.triggerReload(true);
}
}
};
private ActivityDownloadBinding binding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityDownloadBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appbar.toolbar);
binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
mPref = XposedApp.getPreferences();
mRepoLoader = RepoLoader.getInstance();
mModuleUtil = ModuleUtil.getInstance();
mAdapter = new DownloadsAdapter(this, RepoDb.queryModuleOverview(mSortingOrder, mFilterText));
/*mAdapter.setFilterQueryProvider(new FilterQueryProvider() {
setupWindowInsets(binding.snackbar, binding.recyclerView);
repoLoader = RepoLoader.getInstance();
moduleUtil = ModuleUtil.getInstance();
adapter = new DownloadsAdapter(this, RepoDb.queryModuleOverview(sortingOrder, filterText));
/*adapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
return RepoDb.queryModuleOverview(mSortingOrder, constraint);
return RepoDb.queryModuleOverview(sortingOrder, constraint);
}
});*/
mSortingOrder = mPref.getInt("download_sorting_order",
RepoDb.SORT_STATUS);
sortingOrder = XposedApp.getPreferences().getInt("download_sorting_order", RepoDb.SORT_STATUS);
mIgnoredUpdatesPref = getSharedPreferences("update_ignored", MODE_PRIVATE);
RecyclerView mListView = findViewById(R.id.recyclerView);
ignoredUpdatesPref = getSharedPreferences("update_ignored", MODE_PRIVATE);
if (Build.VERSION.SDK_INT >= 26) {
mListView.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
binding.recyclerView.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}
final SwipeRefreshLayout refreshLayout = findViewById(R.id.swipeRefreshLayout);
refreshLayout.setOnRefreshListener(() -> {
mRepoLoader.setSwipeRefreshLayout(refreshLayout);
mRepoLoader.triggerReload(true);
binding.swipeRefreshLayout.setOnRefreshListener(() -> {
repoLoader.setSwipeRefreshLayout(binding.swipeRefreshLayout);
repoLoader.triggerReload(true);
});
mRepoLoader.addListener(this, true);
mModuleUtil.addListener(this);
mListView.setAdapter(mAdapter);
repoLoader.addListener(this, true);
moduleUtil.addListener(this);
binding.recyclerView.setAdapter(adapter);
mListView.setLayoutManager(new LinearLayoutManager(this));
StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(mAdapter);
mListView.addItemDecoration(headersDecor);
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(adapter);
binding.recyclerView.addItemDecoration(headersDecor);
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
headersDecor.invalidateHeaders();
}
});
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mListView.getContext(),
DividerItemDecoration.VERTICAL);
mListView.addItemDecoration(dividerItemDecoration);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
binding.recyclerView.addItemDecoration(dividerItemDecoration);
}
@ -122,7 +116,7 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
public void onResume() {
super.onResume();
mIgnoredUpdatesPref.registerOnSharedPreferenceChangeListener(this);
ignoredUpdatesPref.registerOnSharedPreferenceChangeListener(this);
if (changed) {
reloadItems();
changed = !changed;
@ -142,9 +136,9 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
public void onDestroy() {
super.onDestroy();
mRepoLoader.removeListener(this);
mModuleUtil.removeListener(this);
mIgnoredUpdatesPref.unregisterOnSharedPreferenceChangeListener(this);
repoLoader.removeListener(this);
moduleUtil.removeListener(this);
ignoredUpdatesPref.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
@ -152,13 +146,13 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
getMenuInflater().inflate(R.menu.menu_download, menu);
// Setup search button
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
mSearchView.setIconifiedByDefault(true);
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setIconifiedByDefault(true);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
setFilter(query);
mSearchView.clearFocus();
searchView.clearFocus();
return true;
}
@ -172,14 +166,14 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
}
private void setFilter(String filterText) {
mFilterText = filterText;
this.filterText = filterText;
reloadItems();
}
private void reloadItems() {
runOnUiThread(() -> {
mAdapter.swapCursor(RepoDb.queryModuleOverview(mSortingOrder, mFilterText));
mAdapter.notifyDataSetChanged();
adapter.swapCursor(RepoDb.queryModuleOverview(sortingOrder, filterText));
adapter.notifyDataSetChanged();
});
}
@ -188,9 +182,9 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
if (item.getItemId() == R.id.menu_sort) {
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.download_sorting_title)
.setSingleChoiceItems(R.array.download_sort_order, mSortingOrder, (dialog, which) -> {
mSortingOrder = which;
mPref.edit().putInt("download_sorting_order", mSortingOrder).apply();
.setSingleChoiceItems(R.array.download_sort_order, sortingOrder, (dialog, which) -> {
sortingOrder = which;
XposedApp.getPreferences().edit().putInt("download_sorting_order", sortingOrder).apply();
reloadItems();
dialog.dismiss();
})
@ -222,23 +216,23 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
@Override
public void onBackPressed() {
if (mSearchView.isIconified()) {
if (searchView.isIconified()) {
super.onBackPressed();
} else {
mSearchView.setIconified(true);
searchView.setIconified(true);
}
}
private class DownloadsAdapter extends CursorRecyclerViewAdapter<DownloadsAdapter.ViewHolder> implements StickyRecyclerHeadersAdapter {
private final Context mContext;
private final DateFormat mDateFormatter = DateFormat.getDateInstance(DateFormat.SHORT);
private final SharedPreferences mPrefs;
private final Context context;
private final DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT);
private final SharedPreferences prefs;
private String[] sectionHeaders;
DownloadsAdapter(Context context, Cursor cursor) {
super(context, cursor);
mContext = context;
mPrefs = context.getSharedPreferences("update_ignored", MODE_PRIVATE);
this.context = context;
prefs = context.getSharedPreferences("update_ignored", MODE_PRIVATE);
Resources res = context.getResources();
sectionHeaders = new String[]{
@ -260,7 +254,7 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
long updated = cursor.getLong(RepoDbDefinitions.OverviewColumnsIndexes.UPDATED);
boolean isFramework = cursor.getInt(RepoDbDefinitions.OverviewColumnsIndexes.IS_FRAMEWORK) > 0;
boolean isInstalled = cursor.getInt(RepoDbDefinitions.OverviewColumnsIndexes.IS_INSTALLED) > 0;
boolean updateIgnored = mPrefs.getBoolean(cursor.getString(RepoDbDefinitions.OverviewColumnsIndexes.PKGNAME), false);
boolean updateIgnored = prefs.getBoolean(cursor.getString(RepoDbDefinitions.OverviewColumnsIndexes.PKGNAME), false);
boolean updateIgnorePreference = XposedApp.getPreferences().getBoolean("ignore_updates", false);
boolean hasUpdate = cursor.getInt(RepoDbDefinitions.OverviewColumnsIndexes.HAS_UPDATE) > 0;
@ -268,8 +262,8 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
hasUpdate = false;
}
if (mSortingOrder != RepoDb.SORT_STATUS) {
long timestamp = (mSortingOrder == RepoDb.SORT_UPDATED) ? updated : created;
if (sortingOrder != RepoDb.SORT_STATUS) {
long timestamp = (sortingOrder == RepoDb.SORT_UPDATED) ? updated : created;
long age = System.currentTimeMillis() - timestamp;
final long mSecsPerDay = 24 * 60 * 60 * 1000L;
if (age < mSecsPerDay)
@ -309,8 +303,8 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_download, parent, false);
return new ViewHolder(v);
ItemDownloadBinding binding = ItemDownloadBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolder(binding);
}
@Override
@ -322,7 +316,7 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
long created = cursor.getLong(RepoDbDefinitions.OverviewColumnsIndexes.CREATED);
long updated = cursor.getLong(RepoDbDefinitions.OverviewColumnsIndexes.UPDATED);
boolean isInstalled = cursor.getInt(RepoDbDefinitions.OverviewColumnsIndexes.IS_INSTALLED) > 0;
boolean updateIgnored = mPrefs.getBoolean(cursor.getString(RepoDbDefinitions.OverviewColumnsIndexes.PKGNAME), false);
boolean updateIgnored = prefs.getBoolean(cursor.getString(RepoDbDefinitions.OverviewColumnsIndexes.PKGNAME), false);
boolean updateIgnorePreference = XposedApp.getPreferences().getBoolean("ignore_updates", false);
boolean hasUpdate = cursor.getInt(RepoDbDefinitions.OverviewColumnsIndexes.HAS_UPDATE) > 0;
@ -338,13 +332,13 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
TextView txtStatus = holder.downloadStatus;
if (hasUpdate) {
txtStatus.setText(mContext.getString(
txtStatus.setText(context.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(
txtStatus.setText(context.getString(
R.string.download_status_installed, installedVersion));
txtStatus.setTextColor(getResources().getColor(R.color.warning));
TypedArray typedArray = DownloadActivity.this.getTheme().obtainStyledAttributes(new int[]{android.R.attr.textColorHighlight});
@ -356,8 +350,8 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
txtStatus.setVisibility(View.GONE);
}
String creationDate = mDateFormatter.format(new Date(created));
String updateDate = mDateFormatter.format(new Date(updated));
String creationDate = dateFormatter.format(new Date(created));
String updateDate = dateFormatter.format(new Date(updated));
holder.timestamps.setText(getString(R.string.download_timestamps, creationDate, updateDate));
String packageName = cursor.getString(RepoDbDefinitions.OverviewColumnsIndexes.PKGNAME);
holder.itemView.setOnClickListener(v -> {
@ -373,12 +367,12 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
TextView downloadStatus;
TextView timestamps;
ViewHolder(View itemView) {
super(itemView);
appName = itemView.findViewById(R.id.title);
appDescription = itemView.findViewById(R.id.description);
downloadStatus = itemView.findViewById(R.id.downloadStatus);
timestamps = itemView.findViewById(R.id.timestamps);
ViewHolder(ItemDownloadBinding binding) {
super(binding.getRoot());
appName = binding.title;
appDescription = binding.description;
downloadStatus = binding.downloadStatus;
timestamps = binding.timestamps;
}
}
}

View File

@ -11,18 +11,15 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import org.meowcat.edxposed.manager.databinding.ActivityDownloadDetailsBinding;
import org.meowcat.edxposed.manager.databinding.ActivityDownloadDetailsNotFoundBinding;
import org.meowcat.edxposed.manager.repo.Module;
import org.meowcat.edxposed.manager.util.ModuleUtil;
import org.meowcat.edxposed.manager.util.RepoLoader;
@ -39,37 +36,37 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
static final String PLAY_STORE_PACKAGE = "com.android.vending";
static final String PLAY_STORE_LINK = "https://play.google.com/store/apps/details?id=%s";
private static final String TAG = "DownloadDetailsActivity";
private static RepoLoader sRepoLoader = RepoLoader.getInstance();
private static ModuleUtil sModuleUtil = ModuleUtil.getInstance();
private ViewPager mPager;
private String mPackageName;
private Module mModule;
private ModuleUtil.InstalledModule mInstalledModule;
private static RepoLoader repoLoader = RepoLoader.getInstance();
private static ModuleUtil moduleUtil = ModuleUtil.getInstance();
private String packageName;
private Module module;
private ModuleUtil.InstalledModule installedModule;
private ActivityDownloadDetailsBinding binding;
@Override
public void onCreate(Bundle savedInstanceState) {
mPackageName = getModulePackageName();
packageName = getModulePackageName();
try {
mModule = sRepoLoader.getModule(mPackageName);
module = repoLoader.getModule(packageName);
} catch (Exception e) {
Log.i(TAG, "DownloadDetailsActivity -> " + e.getMessage());
mModule = null;
module = null;
}
mInstalledModule = ModuleUtil.getInstance().getModule(mPackageName);
installedModule = ModuleUtil.getInstance().getModule(packageName);
super.onCreate(savedInstanceState);
sRepoLoader.addListener(this, false);
sModuleUtil.addListener(this);
repoLoader.addListener(this, false);
moduleUtil.addListener(this);
if (mModule != null) {
setContentView(R.layout.activity_download_details);
if (module != null) {
binding = ActivityDownloadDetailsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
setSupportActionBar(binding.toolbar);
binding.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar ab = getSupportActionBar();
@ -81,28 +78,26 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
boolean directDownload = getIntent().getBooleanExtra("direct_download", false);
// Updates available => start on the versions page
if (mInstalledModule != null && mInstalledModule.isUpdate(sRepoLoader.getLatestVersion(mModule)) || directDownload)
mPager.setCurrentItem(DOWNLOAD_VERSIONS);
if (installedModule != null && installedModule.isUpdate(repoLoader.getLatestVersion(module)) || directDownload)
binding.downloadPager.setCurrentItem(DOWNLOAD_VERSIONS);
} else {
setContentView(R.layout.activity_download_details_not_found);
ActivityDownloadDetailsNotFoundBinding binding = ActivityDownloadDetailsNotFoundBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
TextView txtMessage = findViewById(android.R.id.message);
txtMessage.setText(getResources().getString(R.string.download_details_not_found, mPackageName));
binding.message.setText(getResources().getString(R.string.download_details_not_found, packageName));
findViewById(R.id.reload).setOnClickListener(v -> {
binding.reload.setOnClickListener(v -> {
v.setEnabled(false);
sRepoLoader.triggerReload(true);
repoLoader.triggerReload(true);
});
}
setupWindowInsets();
setupWindowInsets(binding.snackbar, null);
}
private void setupTabs() {
mPager = findViewById(R.id.download_pager);
mPager.setAdapter(new SwipeFragmentPagerAdapter(getSupportFragmentManager()));
TabLayout mTabLayout = findViewById(R.id.sliding_tabs);
mTabLayout.setupWithViewPager(mPager);
binding.downloadPager.setAdapter(new SwipeFragmentPagerAdapter(getSupportFragmentManager()));
binding.slidingTabs.setupWithViewPager(binding.downloadPager);
}
private String getModulePackageName() {
@ -129,20 +124,20 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
@Override
protected void onDestroy() {
super.onDestroy();
sRepoLoader.removeListener(this);
sModuleUtil.removeListener(this);
repoLoader.removeListener(this);
moduleUtil.removeListener(this);
}
public Module getModule() {
return mModule;
return module;
}
public ModuleUtil.InstalledModule getInstalledModule() {
return mInstalledModule;
return installedModule;
}
public void gotoPage(int page) {
mPager.setCurrentItem(page);
binding.downloadPager.setCurrentItem(page);
}
private void reload() {
@ -161,7 +156,7 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
@Override
public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, ModuleUtil.InstalledModule module) {
if (packageName.equals(mPackageName))
if (this.packageName.equals(packageName))
reload();
}
@ -174,7 +169,7 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
if (updateIgnorePreference) {
SharedPreferences prefs = getSharedPreferences("update_ignored", MODE_PRIVATE);
boolean ignored = prefs.getBoolean(mModule.packageName, false);
boolean ignored = prefs.getBoolean(module.packageName, false);
menu.findItem(R.id.ignoreUpdate).setChecked(ignored);
} else {
menu.removeItem(R.id.ignoreUpdate);
@ -189,10 +184,10 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
RepoLoader.getInstance().triggerReload(true);
return true;
case R.id.menu_share:
String text = mModule.name + " - ";
String text = module.name + " - ";
if (isPackageInstalled(mPackageName, this)) {
String s = getPackageManager().getInstallerPackageName(mPackageName);
if (isPackageInstalled(packageName, this)) {
String s = getPackageManager().getInstallerPackageName(packageName);
boolean playStore;
try {
@ -202,13 +197,13 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
}
if (playStore) {
text += String.format(PLAY_STORE_LINK, mPackageName);
text += String.format(PLAY_STORE_LINK, packageName);
} else {
text += String.format(XPOSED_REPO_LINK, mPackageName);
text += String.format(XPOSED_REPO_LINK, packageName);
}
} else {
text += String.format(XPOSED_REPO_LINK,
mPackageName);
packageName);
}
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
@ -219,8 +214,8 @@ public class DownloadDetailsActivity extends BaseActivity implements RepoLoader.
case R.id.ignoreUpdate:
SharedPreferences prefs = getSharedPreferences("update_ignored", MODE_PRIVATE);
boolean ignored = prefs.getBoolean(mModule.packageName, false);
prefs.edit().putBoolean(mModule.packageName, !ignored).apply();
boolean ignored = prefs.getBoolean(module.packageName, false);
prefs.edit().putBoolean(module.packageName, !ignored).apply();
item.setChecked(!ignored);
break;
}

View File

@ -8,12 +8,14 @@ import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import org.meowcat.edxposed.manager.databinding.DownloadDetailsBinding;
import org.meowcat.edxposed.manager.databinding.DownloadMoreinfoBinding;
import org.meowcat.edxposed.manager.repo.Module;
import org.meowcat.edxposed.manager.repo.RepoParser;
import org.meowcat.edxposed.manager.util.NavUtil;
@ -32,50 +34,47 @@ public class DownloadDetailsFragment extends Fragment {
if (module == null) {
return null;
}
final View view = inflater.inflate(R.layout.download_details, container, false);
DownloadDetailsBinding binding = DownloadDetailsBinding.inflate(inflater, container, false);
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
binding.getRoot().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
return insets;
});
binding.downloadTitle.setText(module.name);
binding.downloadTitle.setTextIsSelectable(true);
TextView title = view.findViewById(R.id.download_title);
title.setText(module.name);
title.setTextIsSelectable(true);
TextView author = view.findViewById(R.id.download_author);
if (module.author != null && !module.author.isEmpty())
author.setText(getString(R.string.download_author, module.author));
binding.downloadAuthor.setText(getString(R.string.download_author, module.author));
else
author.setText(R.string.download_unknown_author);
binding.downloadAuthor.setText(R.string.download_unknown_author);
TextView description = view.findViewById(R.id.download_description);
if (module.description != null) {
if (module.descriptionIsHtml) {
description.setText(RepoParser.parseSimpleHtml(getActivity(), module.description, description));
description.setTransformationMethod(new LinkTransformationMethod((AppCompatActivity) getActivity()));
description.setMovementMethod(LinkMovementMethod.getInstance());
binding.downloadDescription.setText(RepoParser.parseSimpleHtml(getActivity(), module.description, binding.downloadDescription));
binding.downloadDescription.setTransformationMethod(new LinkTransformationMethod((AppCompatActivity) getActivity()));
binding.downloadDescription.setMovementMethod(LinkMovementMethod.getInstance());
} else {
description.setText(module.description);
binding.downloadDescription.setText(module.description);
}
description.setTextIsSelectable(true);
binding.downloadDescription.setTextIsSelectable(true);
} else {
description.setVisibility(View.GONE);
binding.downloadDescription.setVisibility(View.GONE);
}
ViewGroup moreInfoContainer = view.findViewById(R.id.download_moreinfo_container);
for (Pair<String, String> moreInfoEntry : module.moreInfo) {
View moreInfoView = inflater.inflate(R.layout.download_moreinfo, moreInfoContainer, false);
TextView txtTitle = moreInfoView.findViewById(android.R.id.title);
TextView txtValue = moreInfoView.findViewById(android.R.id.message);
DownloadMoreinfoBinding moreinfoBinding = DownloadMoreinfoBinding.inflate(inflater, binding.downloadMoreinfoContainer, false);
txtTitle.setText(moreInfoEntry.first + ":");
txtValue.setText(moreInfoEntry.second);
moreinfoBinding.title.setText(moreInfoEntry.first + ":");
moreinfoBinding.message.setText(moreInfoEntry.second);
final Uri link = NavUtil.parseURL(moreInfoEntry.second);
if (link != null) {
txtValue.setTextColor(txtValue.getLinkTextColors());
moreInfoView.setOnClickListener(v -> NavUtil.startURL((AppCompatActivity) getActivity(), link));
moreinfoBinding.message.setTextColor(moreinfoBinding.message.getLinkTextColors());
moreinfoBinding.getRoot().setOnClickListener(v -> NavUtil.startURL((AppCompatActivity) getActivity(), link));
}
moreInfoContainer.addView(moreInfoView);
binding.downloadMoreinfoContainer.addView(moreinfoBinding.getRoot());
}
return view;
return binding.getRoot();
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import com.takisoft.preferencex.PreferenceFragmentCompat;
@ -16,7 +17,6 @@ import java.util.Map;
public class DownloadDetailsSettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) {
DownloadDetailsActivity mActivity = (DownloadDetailsActivity) getActivity();
@ -48,11 +48,13 @@ public class DownloadDetailsSettingsFragment extends PreferenceFragmentCompat {
editor.putBoolean("no_global", false).apply();
}
findPreference("release_type").setOnPreferenceChangeListener(
(preference, newValue) -> {
RepoLoader.getInstance().setReleaseTypeLocal(packageName, (String) newValue);
return true;
});
Preference releaseType = findPreference("release_type");
if (releaseType != null) {
releaseType.setOnPreferenceChangeListener((preference, newValue) -> {
RepoLoader.getInstance().setReleaseTypeLocal(packageName, (String) newValue);
return true;
});
}
}
}

View File

@ -19,8 +19,10 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.ListFragment;
import com.google.android.material.snackbar.Snackbar;
@ -44,18 +46,17 @@ import java.text.DateFormat;
import java.util.Date;
public class DownloadDetailsVersionsFragment extends ListFragment {
private static View rootView;
private DownloadDetailsActivity mActivity;
@SuppressLint("StaticFieldLeak")
private DownloadDetailsActivity activity;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = (DownloadDetailsActivity) getActivity();
if (mActivity == null) {
activity = (DownloadDetailsActivity) getActivity();
if (activity == null) {
return;
}
rootView = mActivity.findViewById(R.id.snackbar);
Module module = mActivity.getModule();
Module module = activity.getModule();
if (module == null)
return;
@ -68,25 +69,32 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
TextView txtHeader = new TextView(getActivity());
txtHeader.setText(R.string.download_test_version_not_shown);
txtHeader.setTextColor(getResources().getColor(R.color.warning));
txtHeader.setOnClickListener(v -> mActivity.gotoPage(DownloadDetailsActivity.DOWNLOAD_SETTINGS));
txtHeader.setOnClickListener(v -> activity.gotoPage(DownloadDetailsActivity.DOWNLOAD_SETTINGS));
getListView().addHeaderView(txtHeader);
}
VersionsAdapter sAdapter = new VersionsAdapter(mActivity, mActivity.getInstalledModule());
VersionsAdapter sAdapter = new VersionsAdapter(activity, activity.getInstalledModule(), activity.findViewById(R.id.snackbar));
for (ModuleVersion version : module.versions) {
if (repoLoader.isVersionShown(version))
sAdapter.add(version);
}
setListAdapter(sAdapter);
}
if (getView() != null) {
((FrameLayout) getView()).setClipChildren(false);
((FrameLayout) getView()).setClipToPadding(false);
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((FrameLayout) view).setClipChildren(false);
((FrameLayout) view).setClipToPadding(false);
((FrameLayout) getListView().getParent()).setClipChildren(false);
((FrameLayout) getListView().getParent()).setClipToPadding(false);
getListView().setClipToPadding(false);
getListView().setClipToPadding(false);
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> {
getListView().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
return insets;
});
}
@Override
@ -106,7 +114,7 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
Uri uri = data.getData();
if (uri != null) {
try {
OutputStream os = mActivity.getContentResolver().openOutputStream(uri);
OutputStream os = activity.getContentResolver().openOutputStream(uri);
if (os != null) {
FileInputStream in = new FileInputStream(new File(DownloadView.lastInfo.localFilename));
byte[] buffer = new byte[1024];
@ -137,9 +145,11 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
public static class DownloadModuleCallback implements DownloadsUtil.DownloadFinishedCallback {
private final ModuleVersion moduleVersion;
private View snackbar;
DownloadModuleCallback(ModuleVersion moduleVersion) {
DownloadModuleCallback(ModuleVersion moduleVersion, View snackbar) {
this.moduleVersion = moduleVersion;
this.snackbar = snackbar;
}
@Override
@ -152,12 +162,12 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
try {
String actualMd5Sum = HashUtil.md5(localFile);
if (!moduleVersion.md5sum.equals(actualMd5Sum)) {
Snackbar.make(rootView, context.getString(R.string.download_md5sum_incorrect, actualMd5Sum, moduleVersion.md5sum), Snackbar.LENGTH_LONG).show();
Snackbar.make(snackbar, context.getString(R.string.download_md5sum_incorrect, actualMd5Sum, moduleVersion.md5sum), Snackbar.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
} catch (Exception e) {
Snackbar.make(rootView, context.getString(R.string.download_could_not_read_file, e.getMessage()), Snackbar.LENGTH_LONG).show();
Snackbar.make(snackbar, context.getString(R.string.download_could_not_read_file, e.getMessage()), Snackbar.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
@ -167,13 +177,13 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
PackageInfo packageInfo = pm.getPackageArchiveInfo(info.localFilename, 0);
if (packageInfo == null) {
Snackbar.make(rootView, R.string.download_no_valid_apk, Snackbar.LENGTH_LONG).show();
Snackbar.make(snackbar, R.string.download_no_valid_apk, Snackbar.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
if (!packageInfo.packageName.equals(moduleVersion.module.packageName)) {
Snackbar.make(rootView, context.getString(R.string.download_incorrect_package_name, packageInfo.packageName, moduleVersion.module.packageName), Snackbar.LENGTH_LONG).show();
Snackbar.make(snackbar, context.getString(R.string.download_incorrect_package_name, packageInfo.packageName, moduleVersion.module.packageName), Snackbar.LENGTH_LONG).show();
DownloadsUtil.removeById(context, info.id);
return;
}
@ -183,29 +193,31 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
}
private class VersionsAdapter extends ArrayAdapter<ModuleVersion> {
private final DateFormat mDateFormatter = DateFormat
private final DateFormat dateFormatter = DateFormat
.getDateInstance(DateFormat.SHORT);
private final int mColorRelTypeStable;
private final int mColorRelTypeOthers;
private final int mColorInstalled;
private final int mColorUpdateAvailable;
private final String mTextInstalled;
private final String mTextUpdateAvailable;
private final long mInstalledVersionCode;
private final int colorRelTypeStable;
private final int colorRelTypeOthers;
private final int colorInstalled;
private final int colorUpdateAvailable;
private final String textInstalled;
private final String textUpdateAvailable;
private final long installedVersionCode;
private View snackbar;
VersionsAdapter(Context context, InstalledModule installed) {
VersionsAdapter(Context context, InstalledModule installed, View snackbar) {
super(context, R.layout.item_version);
TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme();
theme.resolveAttribute(android.R.attr.textColorPrimary, typedValue, true);
int color = ContextCompat.getColor(context, typedValue.resourceId);
mColorRelTypeStable = color;
mColorRelTypeOthers = getResources().getColor(R.color.warning);
mColorInstalled = color;
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;
colorRelTypeStable = color;
colorRelTypeOthers = getResources().getColor(R.color.warning);
colorInstalled = color;
colorUpdateAvailable = getResources().getColor(R.color.download_status_update_available);
textInstalled = getString(R.string.download_section_installed) + ":";
textUpdateAvailable = getString(R.string.download_section_update_available) + ":";
installedVersionCode = (installed != null) ? installed.versionCode : -1;
this.snackbar = snackbar;
}
@SuppressLint("InflateParams")
@ -236,32 +248,32 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
holder.txtVersion.setText(item.name);
holder.txtRelType.setText(item.relType.getTitleId());
holder.txtRelType.setTextColor(item.relType == ReleaseType.STABLE
? mColorRelTypeStable : mColorRelTypeOthers);
? colorRelTypeStable : colorRelTypeOthers);
if (item.uploaded > 0) {
holder.txtUploadDate.setText(
mDateFormatter.format(new Date(item.uploaded)));
dateFormatter.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 || installedVersionCode <= 0
|| item.code < installedVersionCode) {
holder.txtStatus.setVisibility(View.GONE);
} else if (item.code == mInstalledVersionCode) {
holder.txtStatus.setText(mTextInstalled);
holder.txtStatus.setTextColor(mColorInstalled);
} else if (item.code == installedVersionCode) {
holder.txtStatus.setText(textInstalled);
holder.txtStatus.setTextColor(colorInstalled);
holder.txtStatus.setVisibility(View.VISIBLE);
} else { // item.code > mInstalledVersionCode
holder.txtStatus.setText(mTextUpdateAvailable);
holder.txtStatus.setTextColor(mColorUpdateAvailable);
} else { // item.code > installedVersionCode
holder.txtStatus.setText(textUpdateAvailable);
holder.txtStatus.setTextColor(colorUpdateAvailable);
holder.txtStatus.setVisibility(View.VISIBLE);
}
holder.downloadView.setUrl(item.downloadLink);
holder.downloadView.setTitle(mActivity.getModule().name);
holder.downloadView.setDownloadFinishedCallback(new DownloadModuleCallback(item));
holder.downloadView.setTitle(activity.getModule().name);
holder.downloadView.setDownloadFinishedCallback(new DownloadModuleCallback(item, snackbar));
if (item.changelog != null && !item.changelog.isEmpty()) {
holder.txtChangesTitle.setVisibility(View.VISIBLE);

View File

@ -1,65 +1,58 @@
package org.meowcat.edxposed.manager;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.checkbox.MaterialCheckBox;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.tabs.TabLayout;
import com.google.gson.Gson;
import org.meowcat.edxposed.manager.databinding.ActivityEdDownloadBinding;
import org.meowcat.edxposed.manager.databinding.DialogInstallWarningBinding;
import org.meowcat.edxposed.manager.util.json.JSONUtils;
import org.meowcat.edxposed.manager.util.json.XposedTab;
import java.util.ArrayList;
public class EdDownloadActivity extends BaseActivity {
ActivityEdDownloadBinding binding;
private TabsAdapter tabsAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ed_download);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityEdDownloadBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
binding.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
ViewPager mPager = findViewById(R.id.pager);
TabLayout mTabLayout = findViewById(R.id.tab_layout);
tabsAdapter = new TabsAdapter(getSupportFragmentManager());
tabsAdapter.notifyDataSetChanged();
mPager.setAdapter(tabsAdapter);
mTabLayout.setupWithViewPager(mPager);
binding.pager.setAdapter(tabsAdapter);
binding.tabLayout.setupWithViewPager(binding.pager);
new JSONParser().execute();
if (!XposedApp.getPreferences().getBoolean("hide_install_warning", false)) {
@SuppressLint("InflateParams") final View dontShowAgainView = getLayoutInflater().inflate(R.layout.dialog_install_warning, null);
DialogInstallWarningBinding binding = DialogInstallWarningBinding.inflate(getLayoutInflater());
binding.message.setText(R.string.not_logcat);
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.install_warning_title)
.setView(dontShowAgainView)
.setView(binding.getRoot())
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
MaterialCheckBox checkBox = dontShowAgainView.findViewById(android.R.id.checkbox);
if (checkBox.isChecked())
if (binding.checkbox.isChecked())
XposedApp.getPreferences().edit().putBoolean("hide_install_warning", true).apply();
})
.setCancelable(false)
@ -78,7 +71,6 @@ public class EdDownloadActivity extends BaseActivity {
return super.onCreateOptionsMenu(menu);
}
@SuppressLint("StaticFieldLeak")
private class JSONParser extends AsyncTask<Void, Void, String> {
@Override

View File

@ -17,16 +17,18 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.checkbox.MaterialCheckBox;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import org.meowcat.edxposed.manager.databinding.ActivityLogsBinding;
import org.meowcat.edxposed.manager.databinding.DialogInstallWarningBinding;
import org.meowcat.edxposed.manager.databinding.ItemLogBinding;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -39,54 +41,48 @@ import java.util.Scanner;
public class LogsActivity extends BaseActivity {
private boolean allLog = false;
private File mFileErrorLog = new File(XposedApp.BASE_DIR + "log/error.log");
private File mFileErrorLogOld = new File(
private File fileErrorLog = new File(XposedApp.BASE_DIR + "log/error.log");
private File fileErrorLogOld = new File(
XposedApp.BASE_DIR + "log/error.log.old");
private File mFileAllLog = new File(XposedApp.BASE_DIR + "log/all.log");
private File mFileAllLogOld = new File(XposedApp.BASE_DIR + "log/all.log.old");
private LogsAdapter mAdapter;
private RecyclerView mListView;
private File fileAllLog = new File(XposedApp.BASE_DIR + "log/all.log");
private File fileAllLogOld = new File(XposedApp.BASE_DIR + "log/all.log.old");
private LogsAdapter adapter;
private Handler handler = new Handler();
private ActivityLogsBinding binding;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logs);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityLogsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
binding.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
setupWindowInsets(binding.snackbar, binding.recyclerView);
if (!XposedApp.getPreferences().getBoolean("hide_logcat_warning", false)) {
@SuppressLint("InflateParams") final View dontShowAgainView = getLayoutInflater().inflate(R.layout.dialog_install_warning, null);
TextView message = dontShowAgainView.findViewById(android.R.id.message);
message.setText(R.string.not_logcat);
DialogInstallWarningBinding binding = DialogInstallWarningBinding.inflate(getLayoutInflater());
binding.message.setText(R.string.not_logcat);
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.install_warning_title)
.setView(dontShowAgainView)
.setView(binding.getRoot())
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
MaterialCheckBox checkBox = dontShowAgainView.findViewById(android.R.id.checkbox);
if (checkBox.isChecked())
if (binding.checkbox.isChecked())
XposedApp.getPreferences().edit().putBoolean("hide_logcat_warning", true).apply();
})
.setCancelable(false)
.show();
}
mAdapter = new LogsAdapter();
mListView = findViewById(R.id.recyclerView);
mListView.setAdapter(mAdapter);
mListView.setLayoutManager(new LinearLayoutManager(this));
TabLayout tabLayout = findViewById(R.id.sliding_tabs);
adapter = new LogsAdapter();
binding.recyclerView.setAdapter(adapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
if (XposedApp.getPreferences().getBoolean("disable_verbose_log", false)) {
tabLayout.setVisibility(View.GONE);
binding.slidingTabs.setVisibility(View.GONE);
}
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
binding.slidingTabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
allLog = tab.getPosition() != 0;
@ -133,7 +129,7 @@ public class LogsActivity extends BaseActivity {
try {
send();
} catch (Exception e) {
Snackbar.make(findViewById(R.id.snackbar), e.getLocalizedMessage(), Snackbar.LENGTH_LONG).show();
Snackbar.make(binding.snackbar, e.getLocalizedMessage(), Snackbar.LENGTH_LONG).show();
}
return true;
case R.id.menu_save:
@ -147,32 +143,32 @@ public class LogsActivity extends BaseActivity {
}
private void scrollTop() {
mListView.smoothScrollToPosition(0);
binding.recyclerView.smoothScrollToPosition(0);
}
private void scrollDown() {
mListView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
binding.recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);
}
private void reloadErrorLog() {
new LogsReader().execute(allLog ? mFileAllLog : mFileErrorLog);
new LogsReader().execute(allLog ? fileAllLog : fileErrorLog);
}
private void clear() {
try {
new FileOutputStream(allLog ? mFileAllLog : mFileErrorLog).close();
new FileOutputStream(allLog ? fileAllLog : fileErrorLog).close();
//noinspection ResultOfMethodCallIgnored
(allLog ? mFileAllLogOld : mFileErrorLogOld).delete();
mAdapter.setEmpty();
Snackbar.make(findViewById(R.id.snackbar), R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
(allLog ? fileAllLogOld : fileErrorLogOld).delete();
adapter.setEmpty();
Snackbar.make(binding.snackbar, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
reloadErrorLog();
} catch (IOException e) {
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_clear_failed) + "n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
Snackbar.make(binding.snackbar, getResources().getString(R.string.logs_clear_failed) + "n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
}
}
private void send() {
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", allLog ? mFileAllLog : mFileErrorLog);
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", allLog ? fileAllLog : fileErrorLog);
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
@ -210,7 +206,7 @@ public class LogsActivity extends BaseActivity {
try {
OutputStream os = getContentResolver().openOutputStream(uri);
if (os != null) {
FileInputStream in = new FileInputStream(allLog ? mFileAllLog : mFileErrorLog);
FileInputStream in = new FileInputStream(allLog ? fileAllLog : fileErrorLog);
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) {
@ -219,7 +215,7 @@ public class LogsActivity extends BaseActivity {
os.close();
}
} catch (Exception e) {
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
Snackbar.make(binding.snackbar, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
}
}
}
@ -269,9 +265,9 @@ public class LogsActivity extends BaseActivity {
@Override
protected void onPostExecute(ArrayList<String> logs) {
if (logs.size() == 0) {
mAdapter.setEmpty();
adapter.setEmpty();
} else {
mAdapter.setLogs(logs);
adapter.setLogs(logs);
}
handler.removeCallbacks(mRunnable);//It loaded so fast that no need to show progress
if (mProgressDialog.isShowing()) {
@ -286,8 +282,8 @@ public class LogsActivity extends BaseActivity {
@NonNull
@Override
public LogsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_log, parent, false);
return new LogsAdapter.ViewHolder(v);
ItemLogBinding binding = ItemLogBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new LogsAdapter.ViewHolder(binding);
}
@Override
@ -298,8 +294,8 @@ public class LogsActivity extends BaseActivity {
int desiredWidth = view.getMeasuredWidth();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = desiredWidth;
if (mListView.getWidth() < desiredWidth) {
mListView.requestLayout();
if (binding.recyclerView.getWidth() < desiredWidth) {
binding.recyclerView.requestLayout();
}
}
@ -308,7 +304,7 @@ public class LogsActivity extends BaseActivity {
this.logs.clear();
this.logs.addAll(logs);
notifyDataSetChanged();
mListView.scrollToPosition(getItemCount() - 1);
binding.recyclerView.scrollToPosition(getItemCount() - 1);
}
void setEmpty() {
@ -325,9 +321,9 @@ public class LogsActivity extends BaseActivity {
class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.log);
ViewHolder(ItemLogBinding binding) {
super(binding.getRoot());
textView = binding.log;
}
}
}

View File

@ -3,72 +3,66 @@ package org.meowcat.edxposed.manager;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.TooltipCompat;
import com.google.android.material.card.MaterialCardView;
import org.meowcat.edxposed.manager.databinding.ActivityMainBinding;
import org.meowcat.edxposed.manager.util.ModuleUtil;
import org.meowcat.edxposed.manager.util.RepoLoader;
public class MainActivity extends BaseActivity implements RepoLoader.RepoListener, ModuleUtil.ModuleListener {
ActivityMainBinding binding;
private RepoLoader mRepoLoader;
@SuppressLint("PrivateResource")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
mRepoLoader = RepoLoader.getInstance();
ModuleUtil.getInstance().addListener(this);
mRepoLoader.addListener(this, false);
findViewById(R.id.activity_main_modules).setOnClickListener(v -> {
binding.modules.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), ModulesActivity.class);
startActivity(intent);
});
findViewById(R.id.activity_main_downloads).setOnClickListener(v -> {
binding.downloads.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), DownloadActivity.class);
startActivity(intent);
});
findViewById(R.id.activity_main_apps).setOnClickListener(v -> {
binding.apps.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), BlackListActivity.class);
startActivity(intent);
});
findViewById(R.id.activity_main_status).setOnClickListener(v -> {
binding.status.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), EdDownloadActivity.class);
startActivity(intent);
});
findViewById(R.id.activity_main_settings).setOnClickListener(v -> {
binding.settings.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), SettingsActivity.class);
startActivity(intent);
});
findViewById(R.id.activity_main_logs).setOnClickListener(v -> {
binding.logs.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), LogsActivity.class);
startActivity(intent);
});
findViewById(R.id.activity_main_about).setOnClickListener(v -> {
binding.about.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), AboutActivity.class);
startActivity(intent);
});
ImageView menu = findViewById(R.id.menu_more);
TooltipCompat.setTooltipText(menu, getString(androidx.appcompat.R.string.abc_action_menu_overflow_description));
menu.setOnClickListener(v -> {
PopupMenu appMenu = new PopupMenu(MainActivity.this, menu);
TooltipCompat.setTooltipText(binding.menuMore, getString(androidx.appcompat.R.string.abc_action_menu_overflow_description));
binding.menuMore.setOnClickListener(v -> {
PopupMenu appMenu = new PopupMenu(MainActivity.this, binding.menuMore);
appMenu.inflate(R.menu.menu_installer);
appMenu.setOnMenuItemClickListener(this::onOptionsItemSelected);
appMenu.show();
@ -79,29 +73,25 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
} catch (NullPointerException e) {
installedXposedVersion = null;
}
MaterialCardView cardView = findViewById(R.id.activity_main_status);
TextView title = findViewById(R.id.activity_main_status_title);
ImageView icon = findViewById(R.id.activity_main_status_icon);
TextView details = findViewById(R.id.activity_main_status_summary);
if (installedXposedVersion != null) {
int installedXposedVersionInt = extractIntPart(installedXposedVersion);
if (installedXposedVersionInt == XposedApp.getXposedVersion()) {
String installedXposedVersionStr = installedXposedVersionInt + ".0";
title.setText(R.string.Activated);
details.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
cardView.setCardBackgroundColor(getResources().getColor(R.color.download_status_update_available));
icon.setImageDrawable(getDrawable(R.drawable.ic_check_circle));
binding.statusTitle.setText(R.string.Activated);
binding.statusSummary.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
binding.status.setCardBackgroundColor(getResources().getColor(R.color.download_status_update_available));
binding.statusIcon.setImageDrawable(getDrawable(R.drawable.ic_check_circle));
} else {
title.setText(R.string.Inactivate);
details.setText(R.string.installed_lollipop_inactive);
cardView.setCardBackgroundColor(getResources().getColor(R.color.amber_500));
icon.setImageDrawable(getDrawable(R.drawable.ic_warning));
binding.statusTitle.setText(R.string.Inactivate);
binding.statusSummary.setText(R.string.installed_lollipop_inactive);
binding.status.setCardBackgroundColor(getResources().getColor(R.color.amber_500));
binding.statusIcon.setImageDrawable(getDrawable(R.drawable.ic_warning));
}
} else {
title.setText(R.string.Install);
details.setText(R.string.InstallDetail);
cardView.setCardBackgroundColor(getResources().getColor(R.color.colorPrimary));
icon.setImageDrawable(getDrawable(R.drawable.ic_error));
binding.statusTitle.setText(R.string.Install);
binding.statusSummary.setText(R.string.InstallDetail);
binding.status.setCardBackgroundColor(getResources().getColor(R.color.colorPrimary));
binding.statusIcon.setImageDrawable(getDrawable(R.drawable.ic_error));
}
notifyDataSetChanged();
}
@ -118,45 +108,19 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
return result;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressLint("SetTextI18n")
private void notifyDataSetChanged() {
runOnUiThread(() -> {
String frameworkUpdateVersion = mRepoLoader.getFrameworkUpdateVersion();
boolean moduleUpdateAvailable = mRepoLoader.hasModuleUpdates();
ModuleUtil.getInstance().getEnabledModules().size();
TextView description = findViewById(R.id.activity_main_modules_summary);
description.setText(String.format(getString(R.string.ModulesDetail), ModuleUtil.getInstance().getEnabledModules().size()));
binding.modulesSummary.setText(String.format(getString(R.string.ModulesDetail), ModuleUtil.getInstance().getEnabledModules().size()));
if (frameworkUpdateVersion != null) {
description = findViewById(R.id.activity_main_status_summary);
description.setText(String.format(getString(R.string.welcome_framework_update_available), frameworkUpdateVersion));
binding.statusSummary.setText(String.format(getString(R.string.welcome_framework_update_available), frameworkUpdateVersion));
}
description = findViewById(R.id.activity_main_download_summary);
if (moduleUpdateAvailable) {
description.setText(R.string.modules_updates_available);
binding.downloadSummary.setText(R.string.modules_updates_available);
} else {
description.setText(R.string.ModuleUptodate);
binding.downloadSummary.setText(R.string.ModuleUptodate);
}
});
}

View File

@ -19,14 +19,13 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.snackbar.Snackbar;
import org.meowcat.edxposed.manager.databinding.ActivityModulesBinding;
import org.meowcat.edxposed.manager.repo.Module;
import org.meowcat.edxposed.manager.repo.ModuleVersion;
import org.meowcat.edxposed.manager.repo.ReleaseType;
@ -60,37 +59,36 @@ import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleListener {
public static final String SETTINGS_CATEGORY = "de.robv.android.xposed.category.MODULE_SETTINGS";
ActivityModulesBinding binding;
private int installedXposedVersion;
private ApplicationFilter filter;
private SearchView mSearchView;
private SearchView searchView;
private SearchView.OnQueryTextListener mSearchListener;
private PackageManager mPm;
private PackageManager pm;
private DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
private ModuleUtil mModuleUtil;
private ModuleAdapter mAdapter = null;
private RecyclerView mListView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private ModuleUtil moduleUtil;
private ModuleAdapter adapter = null;
private Runnable reloadModules = new Runnable() {
public void run() {
String queryStr = mSearchView != null ? mSearchView.getQuery().toString() : "";
String queryStr = searchView != null ? searchView.getQuery().toString() : "";
Collection<ModuleUtil.InstalledModule> showList;
Collection<ModuleUtil.InstalledModule> fullList = mModuleUtil.getModules().values();
Collection<ModuleUtil.InstalledModule> fullList = moduleUtil.getModules().values();
if (queryStr.length() == 0) {
showList = fullList;
} else {
showList = new ArrayList<>();
String filter = queryStr.toLowerCase();
for (ModuleUtil.InstalledModule info : fullList) {
if (lowercaseContains(InstallApkUtil.getAppLabel(info.app, mPm), filter)
if (lowercaseContains(InstallApkUtil.getAppLabel(info.app, pm), filter)
|| lowercaseContains(info.packageName, filter)) {
showList.add(info);
}
}
}
mAdapter.addAll(showList);
mAdapter.notifyDataSetChanged();
mModuleUtil.updateModulesList(false);
mSwipeRefreshLayout.setRefreshing(false);
adapter.addAll(showList);
adapter.notifyDataSetChanged();
moduleUtil.updateModulesList(false);
binding.swipeRefreshLayout.setRefreshing(false);
}
};
private String selectedPackageName;
@ -102,36 +100,33 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_modules);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivityModulesBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appbar.toolbar);
binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
setupWindowInsets(binding.snackbar, binding.recyclerView);
filter = new ApplicationFilter();
mModuleUtil = ModuleUtil.getInstance();
mPm = getPackageManager();
moduleUtil = ModuleUtil.getInstance();
pm = getPackageManager();
installedXposedVersion = XposedApp.getXposedVersion();
if (installedXposedVersion <= 0) {
Snackbar.make(findViewById(R.id.snackbar), R.string.xposed_not_active, Snackbar.LENGTH_LONG).setAction(R.string.Settings, v -> {
Snackbar.make(binding.snackbar, R.string.xposed_not_active, Snackbar.LENGTH_LONG).setAction(R.string.Settings, v -> {
Intent intent = new Intent();
intent.setClass(ModulesActivity.this, SettingsActivity.class);
startActivity(intent);
}).show();
}
mAdapter = new ModuleAdapter();
mModuleUtil.addListener(this);
mListView = findViewById(R.id.recyclerView);
mListView.setAdapter(mAdapter);
mListView.setLayoutManager(new LinearLayoutManager(this));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mListView.getContext(),
DividerItemDecoration.VERTICAL);
mListView.addItemDecoration(dividerItemDecoration);
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(() -> reloadModules.run());
adapter = new ModuleAdapter();
moduleUtil.addListener(this);
binding.recyclerView.setAdapter(adapter);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
binding.recyclerView.addItemDecoration(dividerItemDecoration);
binding.swipeRefreshLayout.setOnRefreshListener(() -> reloadModules.run());
reloadModules.run();
mSearchListener = new SearchView.OnQueryTextListener() {
@Override
@ -152,8 +147,8 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_modules, menu);
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
mSearchView.setOnQueryTextListener(mSearchListener);
searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setOnQueryTextListener(mSearchListener);
return super.onCreateOptionsMenu(menu);
}
@ -180,7 +175,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
os.close();
}
} catch (Exception e) {
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
Snackbar.make(binding.snackbar, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
}
}
}
@ -201,7 +196,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
os.close();
}
} catch (Exception e) {
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
Snackbar.make(binding.snackbar, getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
}
}
}
@ -225,7 +220,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
switch (item.getItemId()) {
case R.id.export_enabled_modules:
if (ModuleUtil.getInstance().getEnabledModules().isEmpty()) {
Snackbar.make(findViewById(R.id.snackbar), R.string.no_enabled_modules, Snackbar.LENGTH_SHORT).show();
Snackbar.make(binding.snackbar, R.string.no_enabled_modules, Snackbar.LENGTH_SHORT).show();
return false;
}
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
@ -238,7 +233,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
Map<String, ModuleUtil.InstalledModule> installedModules = ModuleUtil.getInstance().getModules();
if (installedModules.isEmpty()) {
Snackbar.make(findViewById(R.id.snackbar), R.string.no_installed_modules, Snackbar.LENGTH_SHORT).show();
Snackbar.make(binding.snackbar, R.string.no_installed_modules, Snackbar.LENGTH_SHORT).show();
return false;
}
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
@ -271,7 +266,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
Module m = repoLoader.getModule(line);
if (m == null) {
Snackbar.make(findViewById(R.id.snackbar), getString(R.string.download_details_not_found, line), Snackbar.LENGTH_SHORT).show();
Snackbar.make(binding.snackbar, getString(R.string.download_details_not_found, line), Snackbar.LENGTH_SHORT).show();
} else {
list.add(m);
}
@ -279,11 +274,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
br.close();
} catch (Exception e) {
e.printStackTrace();
Snackbar.make(findViewById(R.id.snackbar), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
Snackbar.make(binding.snackbar, e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
}
for (final Module m : list) {
if (mModuleUtil.getModule(m.packageName) != null) {
if (moduleUtil.getModule(m.packageName) != null) {
continue;
}
ModuleVersion mv = null;
@ -307,20 +302,20 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override
public void onDestroy() {
super.onDestroy();
mModuleUtil.removeListener(this);
mListView.setAdapter(null);
mAdapter = null;
moduleUtil.removeListener(this);
binding.recyclerView.setAdapter(null);
adapter = null;
}
@Override
public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, ModuleUtil.InstalledModule module) {
mModuleUtil.updateModulesList(false);
moduleUtil.updateModulesList(false);
runOnUiThread(reloadModules);
}
@Override
public void onInstalledModulesReloaded(ModuleUtil moduleUtil) {
mModuleUtil.updateModulesList(false);
moduleUtil.updateModulesList(false);
runOnUiThread(reloadModules);
}
@ -340,7 +335,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
if (launchIntent != null) {
startActivity(launchIntent);
} else {
Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
Snackbar.make(binding.snackbar, R.string.module_no_ui, Snackbar.LENGTH_LONG).show();
}
return true;
@ -404,10 +399,10 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override
public void onBackPressed() {
if (mSearchView.isIconified()) {
if (searchView.isIconified()) {
super.onBackPressed();
} else {
mSearchView.setIconified(true);
searchView.setIconified(true);
}
}
@ -485,13 +480,13 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
SwitchCompat mSwitch = holder.mSwitch;
mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
String packageName = item.packageName;
boolean changed = mModuleUtil.isModuleEnabled(packageName) ^ isChecked;
boolean changed = moduleUtil.isModuleEnabled(packageName) ^ isChecked;
if (changed) {
mModuleUtil.setModuleEnabled(packageName, isChecked);
mModuleUtil.updateModulesList(true);
moduleUtil.setModuleEnabled(packageName, isChecked);
moduleUtil.updateModulesList(true);
}
});
mSwitch.setChecked(mModuleUtil.isModuleEnabled(item.packageName));
mSwitch.setChecked(moduleUtil.isModuleEnabled(item.packageName));
TextView warningText = holder.warningText;
if (item.minVersion == 0) {

View File

@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.FileUtils;
import android.view.View;
@ -16,8 +15,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.preference.Preference;
import androidx.preference.SwitchPreferenceCompat;
@ -25,57 +24,49 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.takisoft.preferencex.PreferenceFragmentCompat;
import com.topjohnwu.superuser.Shell;
import org.meowcat.edxposed.manager.databinding.ActivitySettingsBinding;
import org.meowcat.edxposed.manager.util.RepoLoader;
import org.meowcat.edxposed.manager.widget.IntegerListPreference;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Objects;
public class SettingsActivity extends BaseActivity {
ActivitySettingsBinding binding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(view -> finish());
binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appbar.toolbar);
binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar();
if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true);
}
setupWindowInsets();
setupWindowInsets(binding.snackbar, null);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, SettingsFragment.newInstance(findViewById(R.id.snackbar))).commit();
.add(R.id.container, new SettingsFragment()).commit();
}
}
@SuppressWarnings({"ResultOfMethodCallIgnored", "deprecation"})
public static class SettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
static final File mDisableResourcesFlag = new File(XposedApp.BASE_DIR + "conf/disable_resources");
static final File mDynamicModulesFlag = new File(XposedApp.BASE_DIR + "conf/dynamicmodules");
static final File mDeoptBootFlag = new File(XposedApp.BASE_DIR + "conf/deoptbootimage");
static final File mWhiteListModeFlag = new File(XposedApp.BASE_DIR + "conf/usewhitelist");
static final File mBlackWhiteListModeFlag = new File(XposedApp.BASE_DIR + "conf/blackwhitelist");
static final File mDisableVerboseLogsFlag = new File(XposedApp.BASE_DIR + "conf/disable_verbose_log");
static final File mDisableModulesLogsFlag = new File(XposedApp.BASE_DIR + "conf/disable_modules_log");
static final File mVerboseLogProcessID = new File(XposedApp.BASE_DIR + "log/all.pid");
static final File mModulesLogProcessID = new File(XposedApp.BASE_DIR + "log/error.pid");
View rootView;
private Preference stopVerboseLog;
private Preference stopLog;
public static class SettingsFragment extends PreferenceFragmentCompat {
static final File disableResourcesFlag = new File(XposedApp.BASE_DIR + "conf/disable_resources");
static final File dynamicModulesFlag = new File(XposedApp.BASE_DIR + "conf/dynamicmodules");
static final File deoptBootFlag = new File(XposedApp.BASE_DIR + "conf/deoptbootimage");
static final File whiteListModeFlag = new File(XposedApp.BASE_DIR + "conf/usewhitelist");
static final File blackWhiteListModeFlag = new File(XposedApp.BASE_DIR + "conf/blackwhitelist");
static final File disableVerboseLogsFlag = new File(XposedApp.BASE_DIR + "conf/disable_verbose_log");
static final File disableModulesLogsFlag = new File(XposedApp.BASE_DIR + "conf/disable_modules_log");
static final File verboseLogProcessID = new File(XposedApp.BASE_DIR + "log/all.pid");
static final File modulesLogProcessID = new File(XposedApp.BASE_DIR + "log/error.pid");
static SettingsFragment newInstance(View rootView) {
SettingsFragment fragment = new SettingsFragment();
fragment.setRootView(rootView);
return fragment;
}
@SuppressWarnings("SameParameterValue")
@SuppressLint({"WorldReadableFiles", "WorldWriteableFiles"})
static void setFilePermissionsFromMode(String name, int mode) {
int perms = FileUtils.S_IRUSR | FileUtils.S_IWUSR
@ -89,331 +80,337 @@ public class SettingsActivity extends BaseActivity {
FileUtils.setPermissions(name, perms, -1, -1);
}
void setRootView(View rootView) {
this.rootView = rootView;
}
@SuppressLint({"ObsoleteSdkInt", "WorldReadableFiles"})
@Override
public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.prefs);
stopVerboseLog = findPreference("stop_verbose_log");
stopLog = findPreference("stop_log");
findPreference("release_type_global").setOnPreferenceChangeListener((preference, newValue) -> {
RepoLoader.getInstance().setReleaseTypeGlobal((String) newValue);
return true;
});
SwitchPreferenceCompat prefWhiteListMode = findPreference("white_list_switch");
Objects.requireNonNull(prefWhiteListMode).setChecked(mWhiteListModeFlag.exists());
prefWhiteListMode.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mWhiteListModeFlag.getPath());
setFilePermissionsFromMode(mWhiteListModeFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mWhiteListModeFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mWhiteListModeFlag.delete();
}
return (enabled == mWhiteListModeFlag.exists());
});
SwitchPreferenceCompat prefVerboseLogs = findPreference("disable_verbose_log");
Objects.requireNonNull(prefVerboseLogs).setChecked(mDisableVerboseLogsFlag.exists());
prefVerboseLogs.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mDisableVerboseLogsFlag.getPath());
setFilePermissionsFromMode(mDisableVerboseLogsFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mDisableVerboseLogsFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mDisableVerboseLogsFlag.delete();
}
return (enabled == mDisableVerboseLogsFlag.exists());
});
SwitchPreferenceCompat prefModulesLogs = findPreference("disable_modules_log");
Objects.requireNonNull(prefModulesLogs).setChecked(mDisableModulesLogsFlag.exists());
prefModulesLogs.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mDisableModulesLogsFlag.getPath());
setFilePermissionsFromMode(mDisableModulesLogsFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mDisableModulesLogsFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mDisableModulesLogsFlag.delete();
}
return (enabled == mDisableModulesLogsFlag.exists());
});
SwitchPreferenceCompat prefBlackWhiteListMode = findPreference("black_white_list_switch");
Objects.requireNonNull(prefBlackWhiteListMode).setChecked(mBlackWhiteListModeFlag.exists());
prefBlackWhiteListMode.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mBlackWhiteListModeFlag.getPath());
setFilePermissionsFromMode(mBlackWhiteListModeFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mBlackWhiteListModeFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mBlackWhiteListModeFlag.delete();
}
return (enabled == mBlackWhiteListModeFlag.exists());
});
SwitchPreferenceCompat prefEnableDeopt = findPreference("enable_boot_image_deopt");
Objects.requireNonNull(prefEnableDeopt).setChecked(mDeoptBootFlag.exists());
prefEnableDeopt.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mDeoptBootFlag.getPath());
setFilePermissionsFromMode(mDeoptBootFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mDeoptBootFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mDeoptBootFlag.delete();
}
return (enabled == mDeoptBootFlag.exists());
});
SwitchPreferenceCompat prefDynamicResources = findPreference("is_dynamic_modules");
Objects.requireNonNull(prefDynamicResources).setChecked(mDynamicModulesFlag.exists());
prefDynamicResources.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mDynamicModulesFlag.getPath());
setFilePermissionsFromMode(mDynamicModulesFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mDynamicModulesFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mDynamicModulesFlag.delete();
}
return (enabled == mDynamicModulesFlag.exists());
});
SwitchPreferenceCompat prefDisableResources = findPreference("disable_resources");
Objects.requireNonNull(prefDisableResources).setChecked(mDisableResourcesFlag.exists());
prefDisableResources.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mDisableResourcesFlag.getPath());
setFilePermissionsFromMode(mDisableResourcesFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
mDisableResourcesFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
mDisableResourcesFlag.delete();
}
return (enabled == mDisableResourcesFlag.exists());
});
SwitchPreferenceCompat transparent_status_bar = findPreference("transparent_status_bar");
Objects.requireNonNull(transparent_status_bar).setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
Activity activity = getActivity();
if (activity != null && !XposedApp.getPreferences().getBoolean("black_dark_theme", false)) {
if (enabled) {
Objects.requireNonNull(getActivity()).getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.colorActionBar));
} else {
Objects.requireNonNull(getActivity()).getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.colorPrimaryDark));
}
}
return true;
});
Preference compat_mode = findPreference("compat_mode");
if (compat_mode != null) {
compat_mode.setOnPreferenceClickListener(preference -> {
Intent intent = new Intent();
intent.setClass(Objects.requireNonNull(getContext()), CompatListActivity.class);
Objects.requireNonNull(getActivity()).startActivity(intent);
Preference stopVerboseLog = findPreference("stop_verbose_log");
if (stopVerboseLog != null) {
stopVerboseLog.setOnPreferenceClickListener(preference -> {
areYouSure(R.string.stop_verbose_log_summary, (dialog, which) -> Shell.su("kill $(cat " + verboseLogProcessID.getAbsolutePath() + ")").exec());
return true;
});
}
Preference stopLog = findPreference("stop_log");
if (stopLog != null) {
stopLog.setOnPreferenceClickListener(preference -> {
areYouSure(R.string.stop_log_summary, (dialog, which) -> Shell.su("kill $(cat " + modulesLogProcessID.getAbsolutePath() + ")").exec());
return true;
});
}
}
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.contains("theme") || key.equals("ignore_chinese")) {
AppCompatDelegate.setDefaultNightMode(XposedApp.getPreferences().getInt("theme", 0));
Objects.requireNonNull(getActivity()).recreate();
Preference releaseType = findPreference("release_type_global");
if (releaseType != null) {
releaseType.setOnPreferenceChangeListener((preference, newValue) -> {
RepoLoader.getInstance().setReleaseTypeGlobal((String) newValue);
return true;
});
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
SettingsActivity act = (SettingsActivity) getActivity();
if (act == null)
return false;
if (preference.getKey().equals(stopVerboseLog.getKey())) {
new Runnable() {
@Override
public void run() {
areYouSure(R.string.stop_verbose_log_summary, (dialog, which) -> Shell.su("kill $(cat " + mVerboseLogProcessID.getAbsolutePath() + ")").exec());
SwitchPreferenceCompat prefWhiteListMode = findPreference("white_list_switch");
if (prefWhiteListMode != null) {
prefWhiteListMode.setChecked(whiteListModeFlag.exists());
prefWhiteListMode.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(whiteListModeFlag.getPath());
setFilePermissionsFromMode(whiteListModeFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
whiteListModeFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
whiteListModeFlag.delete();
}
};
} else if (preference.getKey().equals(stopLog.getKey())) {
new Runnable() {
@Override
public void run() {
areYouSure(R.string.stop_log_summary, (dialog, which) -> Shell.su("kill $(cat " + mModulesLogProcessID.getAbsolutePath() + ")").exec());
}
};
return (enabled == whiteListModeFlag.exists());
});
}
SwitchPreferenceCompat prefVerboseLogs = findPreference("disable_verbose_log");
if (prefVerboseLogs != null) {
prefVerboseLogs.setChecked(disableVerboseLogsFlag.exists());
prefVerboseLogs.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(disableVerboseLogsFlag.getPath());
setFilePermissionsFromMode(disableVerboseLogsFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
disableVerboseLogsFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
disableVerboseLogsFlag.delete();
}
return (enabled == disableVerboseLogsFlag.exists());
});
}
SwitchPreferenceCompat prefModulesLogs = findPreference("disable_modules_log");
if (prefModulesLogs != null) {
prefModulesLogs.setChecked(disableModulesLogsFlag.exists());
prefModulesLogs.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(disableModulesLogsFlag.getPath());
setFilePermissionsFromMode(disableModulesLogsFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
disableModulesLogsFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
disableModulesLogsFlag.delete();
}
return (enabled == disableModulesLogsFlag.exists());
});
}
SwitchPreferenceCompat prefBlackWhiteListMode = findPreference("black_white_list_switch");
if (prefBlackWhiteListMode != null) {
prefBlackWhiteListMode.setChecked(blackWhiteListModeFlag.exists());
prefBlackWhiteListMode.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(blackWhiteListModeFlag.getPath());
setFilePermissionsFromMode(blackWhiteListModeFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
blackWhiteListModeFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
blackWhiteListModeFlag.delete();
}
return (enabled == blackWhiteListModeFlag.exists());
});
}
SwitchPreferenceCompat prefEnableDeopt = findPreference("enable_boot_image_deopt");
if (prefEnableDeopt != null) {
prefEnableDeopt.setChecked(deoptBootFlag.exists());
prefEnableDeopt.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(deoptBootFlag.getPath());
setFilePermissionsFromMode(deoptBootFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
deoptBootFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
deoptBootFlag.delete();
}
return (enabled == deoptBootFlag.exists());
});
}
SwitchPreferenceCompat prefDynamicResources = findPreference("is_dynamic_modules");
if (prefDynamicResources != null) {
prefDynamicResources.setChecked(dynamicModulesFlag.exists());
prefDynamicResources.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(dynamicModulesFlag.getPath());
setFilePermissionsFromMode(dynamicModulesFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
dynamicModulesFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
dynamicModulesFlag.delete();
}
return (enabled == dynamicModulesFlag.exists());
});
}
SwitchPreferenceCompat prefDisableResources = findPreference("disable_resources");
if (prefDisableResources != null) {
prefDisableResources.setChecked(disableResourcesFlag.exists());
prefDisableResources.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
if (enabled) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(disableResourcesFlag.getPath());
setFilePermissionsFromMode(disableResourcesFlag.getPath(), MODE_WORLD_READABLE);
} catch (FileNotFoundException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
try {
disableResourcesFlag.createNewFile();
} catch (IOException e1) {
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
}
} else {
disableResourcesFlag.delete();
}
return (enabled == disableResourcesFlag.exists());
});
}
SwitchPreferenceCompat transparent = findPreference("transparent_status_bar");
if (transparent != null) {
transparent.setOnPreferenceChangeListener((preference, newValue) -> {
boolean enabled = (Boolean) newValue;
Activity activity = getActivity();
if (activity != null && !XposedApp.getPreferences().getBoolean("black_dark_theme", false)) {
if (enabled) {
activity.getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.colorActionBar));
} else {
activity.getWindow().setStatusBarColor(ContextCompat.getColor(activity, R.color.colorPrimaryDark));
}
}
return true;
});
}
Preference compat_mode = findPreference("compat_mode");
if (compat_mode != null) {
compat_mode.setOnPreferenceClickListener(preference -> {
Activity activity = getActivity();
if (activity != null) {
Intent intent = new Intent();
intent.setClass(activity, CompatListActivity.class);
activity.startActivity(intent);
}
return true;
});
}
IntegerListPreference theme = findPreference("theme");
if (theme != null) {
theme.setOnPreferenceChangeListener((preference, newValue) -> {
AppCompatDelegate.setDefaultNightMode(Integer.parseInt((String) newValue));
return true;
});
}
SwitchPreferenceCompat black_dark_theme = findPreference("black_dark_theme");
if (black_dark_theme != null) {
black_dark_theme.setOnPreferenceChangeListener((preference, newValue) -> {
Activity activity = getActivity();
if (activity != null) {
activity.recreate();
}
return true;
});
}
return true;
}
private void areYouSure(int contentTextId, DialogInterface.OnClickListener listener) {
new MaterialAlertDialogBuilder(Objects.requireNonNull(getActivity())).setTitle(R.string.areyousure)
.setMessage(contentTextId)
.setPositiveButton(android.R.string.yes, listener)
.setNegativeButton(android.R.string.no, null)
.show();
Activity activity = getActivity();
if (activity != null) {
new MaterialAlertDialogBuilder(activity)
.setTitle(R.string.areyousure)
.setMessage(contentTextId)
.setPositiveButton(android.R.string.yes, listener)
.setNegativeButton(android.R.string.no, null)
.show();
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (rootView == null) {
return;
}
//ActionBarShadowController.attachToRecyclerView((AppCompatActivity) getActivity(), getListView());
((LinearLayout) ((FrameLayout) rootView.findViewById(R.id.container)).getChildAt(0)).setClipToPadding(false);
((LinearLayout) ((FrameLayout) rootView.findViewById(R.id.container)).getChildAt(0)).setClipChildren(false);
((FrameLayout) ((LinearLayout) view).getChildAt(0)).setClipChildren(false);
((FrameLayout) ((LinearLayout) view).getChildAt(0)).setClipToPadding(false);
((LinearLayout) view).setClipToPadding(false);
((LinearLayout) view).setClipChildren(false);
((FrameLayout) getListView().getParent()).setClipChildren(false);
((FrameLayout) getListView().getParent()).setClipToPadding(false);
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> {
getListView().setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
return insets;
});
}
}
}

View File

@ -11,14 +11,15 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.meowcat.edxposed.manager.databinding.StatusInstallerBinding;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@ -27,28 +28,25 @@ import java.lang.reflect.Method;
@SuppressLint("StaticFieldLeak")
public class StatusInstallerFragment extends Fragment {
private static StatusInstallerBinding binding;
private static String updateLink;
private static AppCompatActivity sActivity;
private static String mUpdateLink;
private static View mUpdateView;
private static View mUpdateButton;
static void setUpdate(final String link, final String changelog, Context context) {
updateLink = link;
static void setUpdate(final String link, final String changelog, Context mContext) {
mUpdateLink = link;
mUpdateView.setVisibility(View.VISIBLE);
mUpdateButton.setVisibility(View.VISIBLE);
mUpdateButton.setOnClickListener(v -> new MaterialAlertDialogBuilder(sActivity)
binding.updateView.setVisibility(View.VISIBLE);
binding.clickToUpdate.setVisibility(View.VISIBLE);
binding.clickToUpdate.setOnClickListener(v -> new MaterialAlertDialogBuilder(context)
.setTitle(R.string.changes)
.setMessage(Html.fromHtml(changelog))
.setPositiveButton(R.string.update, (dialog, which) -> update(mContext))
.setPositiveButton(R.string.update, (dialog, which) -> update(context))
.setNegativeButton(R.string.later, null).show());
}
private static void update(Context mContext) {
Uri uri = Uri.parse(mUpdateLink);
private static void update(Context context) {
Uri uri = Uri.parse(updateLink);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
mContext.startActivity(intent);
context.startActivity(intent);
}
private static String getCompleteArch() {
@ -73,6 +71,7 @@ public class StatusInstallerFragment extends Fragment {
return info + " (" + getArch() + ")";
}
@SuppressWarnings("deprecation")
private static String getArch() {
if (Build.CPU_ABI.equals("arm64-v8a")) {
return "arm64";
@ -91,20 +90,10 @@ public class StatusInstallerFragment extends Fragment {
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sActivity = (AppCompatActivity) getActivity();
}
@SuppressLint("WorldReadableFiles")
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.status_installer, container, false);
mUpdateView = v.findViewById(R.id.updateView);
mUpdateButton = v.findViewById(R.id.click_to_update);
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = StatusInstallerBinding.inflate(inflater, container, false);
String installedXposedVersion;
try {
@ -113,31 +102,24 @@ public class StatusInstallerFragment extends Fragment {
installedXposedVersion = null;
}
TextView api = v.findViewById(R.id.api);
TextView framework = v.findViewById(R.id.framework);
TextView manager = v.findViewById(R.id.manager);
TextView androidSdk = v.findViewById(R.id.android_version);
TextView manufacturer = v.findViewById(R.id.ic_manufacturer);
TextView cpu = v.findViewById(R.id.cpu);
String mAppVer = "v" + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")";
manager.setText(mAppVer);
binding.manager.setText(mAppVer);
if (installedXposedVersion != null) {
int installedXposedVersionInt = extractIntPart(installedXposedVersion);
String installedXposedVersionStr = installedXposedVersionInt + ".0";
api.setText(installedXposedVersionStr);
framework.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
binding.api.setText(installedXposedVersionStr);
binding.framework.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
}
androidSdk.setText(getString(R.string.android_sdk, getAndroidVersion(), Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
manufacturer.setText(getUIFramework());
cpu.setText(getCompleteArch());
binding.androidVersion.setText(getString(R.string.android_sdk, getAndroidVersion(), Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
binding.manufacturer.setText(getUIFramework());
binding.cpu.setText(getCompleteArch());
determineVerifiedBootState(v);
return v;
determineVerifiedBootState(binding);
return binding.getRoot();
}
private void determineVerifiedBootState(View v) {
private void determineVerifiedBootState(StatusInstallerBinding binding) {
try {
@SuppressLint("PrivateApi") Class<?> c = Class.forName("android.os.SystemProperties");
Method m = c.getDeclaredMethod("get", String.class, String.class);
@ -150,17 +132,16 @@ public class StatusInstallerFragment extends Fragment {
boolean verified = !propSystemVerified.equals("0");
boolean detected = !propState.isEmpty() || fileDmVerityModule.exists();
TextView tv = v.findViewById(R.id.dmverity);
if (verified) {
tv.setText(R.string.verified_boot_active);
tv.setTextColor(getResources().getColor(R.color.warning));
binding.dmverity.setText(R.string.verified_boot_active);
binding.dmverity.setTextColor(getResources().getColor(R.color.warning));
} else if (detected) {
tv.setText(R.string.verified_boot_deactivated);
v.findViewById(R.id.dmverity_explanation).setVisibility(View.GONE);
binding.dmverity.setText(R.string.verified_boot_deactivated);
binding.dmverityExplanation.setVisibility(View.GONE);
} else {
tv.setText(R.string.verified_boot_none);
tv.setTextColor(getResources().getColor(R.color.warning));
v.findViewById(R.id.dmverity_explanation).setVisibility(View.GONE);
binding.dmverity.setText(R.string.verified_boot_none);
binding.dmverity.setTextColor(getResources().getColor(R.color.warning));
binding.dmverityExplanation.setVisibility(View.GONE);
}
} catch (Exception e) {
Log.e(XposedApp.TAG, "Could not detect Verified Boot state", e);
@ -241,7 +222,7 @@ public class StatusInstallerFragment extends Fragment {
case 28:
return "Pie";
case 29:
return "Q";
return "Ten";
case 30:
return "R";
}

View File

@ -47,17 +47,16 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
? "/data/user_de/0/" + BuildConfig.APPLICATION_ID + "/" : BASE_DIR_LEGACY;
public static final String ENABLED_MODULES_LIST_FILE = (Build.VERSION.SDK_INT >= 24
? "/data/user_de/0/" + BuildConfig.APPLICATION_ID + "/" : BASE_DIR_LEGACY) + "conf/enabled_modules.list";
public static int WRITE_EXTERNAL_PERMISSION = 69;
@SuppressLint("StaticFieldLeak")
private static XposedApp mInstance = null;
private static Thread mUiThread;
private static Handler mMainHandler;
private SharedPreferences mPref;
private AppCompatActivity mCurrentActivity = null;
private boolean mIsUiLoaded = false;
private static XposedApp instance = null;
private static Thread uiThread;
private static Handler mainHandler;
private SharedPreferences pref;
private AppCompatActivity currentActivity = null;
private boolean isUiLoaded = false;
public static XposedApp getInstance() {
return mInstance;
return instance;
}
public static InstallZipUtil.XposedProp getXposedProp() {
@ -65,35 +64,19 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
}
public static void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mMainHandler.post(action);
if (Thread.currentThread() != uiThread) {
mainHandler.post(action);
} else {
action.run();
}
}
public static File createFolder() {
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download/EdXposedManager/");
if (!dir.exists()) dir.mkdir();
return dir;
}
// public static void postOnUiThread(Runnable action) {
// mMainHandler.post(action);
// }
public static Integer getXposedVersion() {
return getActiveXposedVersion();
}
public static SharedPreferences getPreferences() {
return mInstance.mPref;
}
public static String getDownloadPath() {
return getPreferences().getString("download_location", Environment.getExternalStorageDirectory() + "/Download/EdXposedManager/");
return instance.pref;
}
public static void mkdirAndChmod(String dir, int permissions) {
@ -134,11 +117,11 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
}
}
mInstance = this;
mUiThread = Thread.currentThread();
mMainHandler = new Handler();
instance = this;
uiThread = Thread.currentThread();
mainHandler = new Handler();
mPref = PreferenceManager.getDefaultSharedPreferences(this);
pref = PreferenceManager.getDefaultSharedPreferences(this);
de.robv.android.xposed.installer.XposedApp.getInstance().reloadXposedProp();
createDirectories();
@ -151,8 +134,8 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
@SuppressLint("SimpleDateFormat") DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = new Date();
if (!Objects.requireNonNull(mPref.getString("date", "")).equals(dateFormat.format(date))) {
mPref.edit().putString("date", dateFormat.format(date)).apply();
if (!Objects.requireNonNull(pref.getString("date", "")).equals(dateFormat.format(date))) {
pref.edit().putString("date", dateFormat.format(date)).apply();
try {
Log.i(TAG, String.format("EdXposedManager - %s - %s", BuildConfig.VERSION_CODE, getPackageManager().getPackageInfo(getPackageName(), 0).versionName));
@ -160,7 +143,7 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
}
}
if (mPref.getBoolean("force_english", false)) {
if (pref.getBoolean("force_english", false)) {
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
@ -189,11 +172,12 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
File[] files = file.listFiles();
if (files != null) for (File f : file.listFiles()) delete(f);
}
//noinspection ResultOfMethodCallIgnored
file.delete();
}
}
@SuppressWarnings("JavaReflectionMemberAccess")
@SuppressWarnings({"JavaReflectionMemberAccess", "OctalInteger"})
@SuppressLint({"PrivateApi", "NewApi"})
private void createDirectories() {
FileUtils.setPermissions(BASE_DIR, 00777, -1, -1);
@ -216,7 +200,7 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
final boolean isLoading = RepoLoader.getInstance().isLoading() || ModuleUtil.getInstance().isLoading();
runOnUiThread(() -> {
synchronized (XposedApp.this) {
if (mCurrentActivity != null) {
if (currentActivity != null) {
if (refreshLayout != null)
refreshLayout.setRefreshing(isLoading);
}
@ -226,12 +210,12 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
@Override
public synchronized void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
if (mIsUiLoaded) {
if (isUiLoaded) {
return;
}
RepoLoader.getInstance().triggerFirstLoadIfNecessary();
mIsUiLoaded = true;
isUiLoaded = true;
}
@Override
@ -241,13 +225,13 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
@Override
public synchronized void onActivityResumed(@NonNull Activity activity) {
mCurrentActivity = (AppCompatActivity) activity;
currentActivity = (AppCompatActivity) activity;
updateProgressIndicator(null);
}
@Override
public synchronized void onActivityPaused(Activity activity) {
mCurrentActivity = null;
currentActivity = null;
}
@Override

View File

@ -4,47 +4,49 @@ import android.content.Context;
import android.database.Cursor;
import android.database.DataSetObserver;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private Context mContext;
@SuppressWarnings("FieldCanBeLocal")
private Context context;
private Cursor mCursor;
private Cursor cursor;
private boolean mDataValid;
private boolean dataValid;
private int mRowIdColumn;
private int rowIdColumn;
private DataSetObserver mDataSetObserver;
private DataSetObserver dataSetObserver;
public CursorRecyclerViewAdapter(Context context, Cursor cursor) {
mContext = context;
mCursor = cursor;
mDataValid = cursor != null;
mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1;
mDataSetObserver = new NotifyingDataSetObserver();
if (mCursor != null) {
mCursor.registerDataSetObserver(mDataSetObserver);
this.context = context;
this.cursor = cursor;
dataValid = cursor != null;
rowIdColumn = dataValid ? cursor.getColumnIndex("_id") : -1;
dataSetObserver = new NotifyingDataSetObserver();
if (this.cursor != null) {
this.cursor.registerDataSetObserver(dataSetObserver);
}
}
public Cursor getCursor() {
return mCursor;
return cursor;
}
@Override
public int getItemCount() {
if (mDataValid && mCursor != null) {
return mCursor.getCount();
if (dataValid && cursor != null) {
return cursor.getCount();
}
return 0;
}
@Override
public long getItemId(int position) {
if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) {
return mCursor.getLong(mRowIdColumn);
if (dataValid && cursor != null && cursor.moveToPosition(position)) {
return cursor.getLong(rowIdColumn);
}
return 0;
}
@ -57,14 +59,14 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
public abstract void onBindViewHolder(VH viewHolder, Cursor cursor);
@Override
public void onBindViewHolder(VH viewHolder, int position) {
if (!mDataValid) {
public void onBindViewHolder(@NonNull VH viewHolder, int position) {
if (!dataValid) {
throw new IllegalStateException("this should only be called when the cursor is valid");
}
if (!mCursor.moveToPosition(position)) {
if (!cursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
onBindViewHolder(viewHolder, mCursor);
onBindViewHolder(viewHolder, cursor);
}
/**
@ -84,24 +86,24 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
* closed.
*/
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == mCursor) {
if (newCursor == cursor) {
return null;
}
final Cursor oldCursor = mCursor;
if (oldCursor != null && mDataSetObserver != null) {
oldCursor.unregisterDataSetObserver(mDataSetObserver);
final Cursor oldCursor = cursor;
if (oldCursor != null && dataSetObserver != null) {
oldCursor.unregisterDataSetObserver(dataSetObserver);
}
mCursor = newCursor;
if (mCursor != null) {
if (mDataSetObserver != null) {
mCursor.registerDataSetObserver(mDataSetObserver);
cursor = newCursor;
if (cursor != null) {
if (dataSetObserver != null) {
cursor.registerDataSetObserver(dataSetObserver);
}
mRowIdColumn = newCursor.getColumnIndexOrThrow("_id");
mDataValid = true;
rowIdColumn = newCursor.getColumnIndexOrThrow("_id");
dataValid = true;
notifyDataSetChanged();
} else {
mRowIdColumn = -1;
mDataValid = false;
rowIdColumn = -1;
dataValid = false;
notifyDataSetChanged();
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
@ -112,14 +114,14 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
@Override
public void onChanged() {
super.onChanged();
mDataValid = true;
dataValid = true;
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
super.onInvalidated();
mDataValid = false;
dataValid = false;
notifyDataSetChanged();
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}

View File

@ -1,6 +1,5 @@
package org.meowcat.edxposed.manager.receivers;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -32,8 +31,7 @@ public class BootReceiver extends BroadcastReceiver {
return netInfo != null && netInfo.isConnectedOrConnecting();
}
@SuppressLint("StaticFieldLeak")
private class CheckUpdates extends AsyncTask<Void, Void, Void> {
private static class CheckUpdates extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {

View File

@ -10,10 +10,15 @@ import org.meowcat.edxposed.manager.util.DownloadsUtil;
public class DownloadReceiver extends BroadcastReceiver {
@Override
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);
DownloadsUtil.triggerDownloadFinishedCallback(context, downloadId);
try {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadsUtil.triggerDownloadFinishedCallback(context, downloadId);
}
} catch (Exception e) {//Flyme
e.printStackTrace();
}
}
}

View File

@ -12,7 +12,7 @@ import org.meowcat.edxposed.manager.util.NotificationUtil;
import java.util.Objects;
public class PackageChangeReceiver extends BroadcastReceiver {
private static ModuleUtil mModuleUtil = null;
private static ModuleUtil moduleUtil = null;
private static String getPackageName(Intent intent) {
Uri uri = intent.getData();
@ -49,22 +49,22 @@ public class PackageChangeReceiver extends BroadcastReceiver {
return;
}
mModuleUtil = getModuleUtilInstance();
moduleUtil = getModuleUtilInstance();
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);
if (moduleUtil.isModuleEnabled(packageName)) {
moduleUtil.setModuleEnabled(packageName, false);
moduleUtil.updateModulesList(false);
}
return;
}
if (mModuleUtil.isModuleEnabled(packageName)) {
mModuleUtil.updateModulesList(false);
if (moduleUtil.isModuleEnabled(packageName)) {
moduleUtil.updateModulesList(false);
NotificationUtil.showModulesUpdatedNotification();
} else {
NotificationUtil.showNotActivatedNotification(packageName, module.getAppName());
@ -72,9 +72,9 @@ public class PackageChangeReceiver extends BroadcastReceiver {
}
private ModuleUtil getModuleUtilInstance() {
if (mModuleUtil == null) {
mModuleUtil = ModuleUtil.getInstance();
if (moduleUtil == null) {
moduleUtil = ModuleUtil.getInstance();
}
return mModuleUtil;
return moduleUtil;
}
}

View File

@ -37,13 +37,13 @@ public final class RepoDb extends SQLiteOpenHelper {
@SuppressLint("StaticFieldLeak")
private static Context context;
private static SQLiteDatabase sDb;
private static SQLiteDatabase db;
static {
RepoDb instance = new RepoDb(XposedApp.getInstance());
sDb = instance.getWritableDatabase();
sDb.execSQL("PRAGMA foreign_keys=ON");
instance.createTempTables(sDb);
db = instance.getWritableDatabase();
db.execSQL("PRAGMA foreign_keys=ON");
instance.createTempTables(db);
}
private RepoDb(Context context) {
@ -56,22 +56,22 @@ public final class RepoDb extends SQLiteOpenHelper {
}
public static void beginTransation() {
sDb.beginTransaction();
db.beginTransaction();
}
public static void setTransactionSuccessful() {
sDb.setTransactionSuccessful();
db.setTransactionSuccessful();
}
public static void endTransation() {
sDb.endTransaction();
db.endTransaction();
}
private static String getString(@SuppressWarnings("SameParameterValue") String table, @SuppressWarnings("SameParameterValue") String searchColumn, String searchValue, @SuppressWarnings("SameParameterValue") String resultColumn) {
String[] projection = new String[]{resultColumn};
String where = searchColumn + " = ?";
String[] whereArgs = new String[]{searchValue};
Cursor c = sDb.query(table, projection, where, whereArgs, null, null, null, "1");
Cursor c = db.query(table, projection, where, whereArgs, null, null, null, "1");
if (c.moveToFirst()) {
String result = c.getString(c.getColumnIndexOrThrow(resultColumn));
c.close();
@ -86,12 +86,12 @@ public final class RepoDb extends SQLiteOpenHelper {
public static long insertRepository(String url) {
ContentValues values = new ContentValues();
values.put(RepositoriesColumns.URL, url);
return sDb.insertOrThrow(RepositoriesColumns.TABLE_NAME, null, values);
return db.insertOrThrow(RepositoriesColumns.TABLE_NAME, null, values);
}
public static void deleteRepositories() {
if (sDb != null)
sDb.delete(RepositoriesColumns.TABLE_NAME, null, null);
if (db != null)
db.delete(RepositoriesColumns.TABLE_NAME, null, null);
}
public static Map<Long, Repository> getRepositories() {
@ -105,7 +105,7 @@ public final class RepoDb extends SQLiteOpenHelper {
RepositoriesColumns.VERSION,
};
Cursor c = sDb.query(RepositoriesColumns.TABLE_NAME, projection, null, null, null, null, RepositoriesColumns._ID);
Cursor c = db.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));
@ -125,13 +125,13 @@ public final class RepoDb extends SQLiteOpenHelper {
values.put(RepositoriesColumns.TITLE, repository.name);
values.put(RepositoriesColumns.PARTIAL_URL, repository.partialUrl);
values.put(RepositoriesColumns.VERSION, repository.version);
sDb.update(RepositoriesColumns.TABLE_NAME, values, RepositoriesColumns._ID + " = ?", new String[]{Long.toString(repoId)});
db.update(RepositoriesColumns.TABLE_NAME, values, RepositoriesColumns._ID + " = ?", new String[]{Long.toString(repoId)});
}
public static void updateRepositoryVersion(long repoId, String version) {
ContentValues values = new ContentValues();
values.put(RepositoriesColumns.VERSION, version);
sDb.update(RepositoriesColumns.TABLE_NAME, values, RepositoriesColumns._ID + " = ?", new String[]{Long.toString(repoId)});
db.update(RepositoriesColumns.TABLE_NAME, values, RepositoriesColumns._ID + " = ?", new String[]{Long.toString(repoId)});
}
@SuppressWarnings("UnusedReturnValue")
@ -150,9 +150,9 @@ public final class RepoDb extends SQLiteOpenHelper {
ModuleVersion latestVersion = RepoLoader.getInstance().getLatestVersion(mod);
sDb.beginTransaction();
db.beginTransaction();
try {
long moduleId = sDb.insertOrThrow(ModulesColumns.TABLE_NAME, null, values);
long moduleId = db.insertOrThrow(ModulesColumns.TABLE_NAME, null, values);
long latestVersionId = -1;
for (ModuleVersion version : mod.versions) {
@ -164,7 +164,7 @@ public final class RepoDb extends SQLiteOpenHelper {
if (latestVersionId > -1) {
values = new ContentValues();
values.put(ModulesColumns.LATEST_VERSION, latestVersionId);
sDb.update(ModulesColumns.TABLE_NAME, values, ModulesColumns._ID + " = ?", new String[]{Long.toString(moduleId)});
db.update(ModulesColumns.TABLE_NAME, values, ModulesColumns._ID + " = ?", new String[]{Long.toString(moduleId)});
}
for (Pair<String, String> moreInfoEntry : mod.moreInfo) {
@ -173,11 +173,11 @@ public final class RepoDb extends SQLiteOpenHelper {
// TODO Add mod.screenshots
sDb.setTransactionSuccessful();
db.setTransactionSuccessful();
return moduleId;
} finally {
sDb.endTransaction();
db.endTransaction();
}
}
@ -192,7 +192,7 @@ public final class RepoDb extends SQLiteOpenHelper {
values.put(ModuleVersionsColumns.CHANGELOG_IS_HTML, version.changelogIsHtml);
values.put(ModuleVersionsColumns.RELTYPE, version.relType.ordinal());
values.put(ModuleVersionsColumns.UPLOADED, version.uploaded);
return sDb.insertOrThrow(ModuleVersionsColumns.TABLE_NAME, null,
return db.insertOrThrow(ModuleVersionsColumns.TABLE_NAME, null,
values);
}
@ -202,15 +202,15 @@ public final class RepoDb extends SQLiteOpenHelper {
values.put(MoreInfoColumns.MODULE_ID, moduleId);
values.put(MoreInfoColumns.LABEL, title);
values.put(MoreInfoColumns.VALUE, value);
return sDb.insertOrThrow(MoreInfoColumns.TABLE_NAME, null, values);
return db.insertOrThrow(MoreInfoColumns.TABLE_NAME, null, values);
}
public static void deleteAllModules(long repoId) {
sDb.delete(ModulesColumns.TABLE_NAME, ModulesColumns.REPO_ID + " = ?", new String[]{Long.toString(repoId)});
db.delete(ModulesColumns.TABLE_NAME, ModulesColumns.REPO_ID + " = ?", new String[]{Long.toString(repoId)});
}
public static void deleteModule(long repoId, String packageName) {
sDb.delete(ModulesColumns.TABLE_NAME, ModulesColumns.REPO_ID + " = ? AND " + ModulesColumns.PKGNAME + " = ?", new String[]{Long.toString(repoId), packageName});
db.delete(ModulesColumns.TABLE_NAME, ModulesColumns.REPO_ID + " = ? AND " + ModulesColumns.PKGNAME + " = ?", new String[]{Long.toString(repoId), packageName});
}
public static Module getModuleByPackageName(String packageName) {
@ -232,7 +232,7 @@ public final class RepoDb extends SQLiteOpenHelper {
String where = ModulesColumns.PREFERRED + " = 1 AND " + ModulesColumns.PKGNAME + " = ?";
String[] whereArgs = new String[]{packageName};
Cursor c = sDb.query(ModulesColumns.TABLE_NAME, projection, where, whereArgs, null, null, null, "1");
Cursor c = db.query(ModulesColumns.TABLE_NAME, projection, where, whereArgs, null, null, null, "1");
if (!c.moveToFirst()) {
c.close();
return null;
@ -267,7 +267,7 @@ public final class RepoDb extends SQLiteOpenHelper {
where = ModuleVersionsColumns.MODULE_ID + " = ?";
whereArgs = new String[]{Long.toString(moduleId)};
c = sDb.query(ModuleVersionsColumns.TABLE_NAME, projection, where, whereArgs, null, null, null);
c = db.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));
@ -291,7 +291,7 @@ public final class RepoDb extends SQLiteOpenHelper {
where = MoreInfoColumns.MODULE_ID + " = ?";
whereArgs = new String[]{Long.toString(moduleId)};
c = sDb.query(MoreInfoColumns.TABLE_NAME, projection, where, whereArgs, null, null, MoreInfoColumns._ID);
c = db.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));
@ -308,7 +308,7 @@ public final class RepoDb extends SQLiteOpenHelper {
public static void updateModuleLatestVersion(String packageName) {
int maxShownReleaseType = RepoLoader.getInstance().getMaxShownReleaseType(packageName).ordinal();
sDb.execSQL("UPDATE " + ModulesColumns.TABLE_NAME
db.execSQL("UPDATE " + ModulesColumns.TABLE_NAME
+ " SET " + ModulesColumns.LATEST_VERSION
+ " = (SELECT " + ModuleVersionsColumns._ID + " FROM " + ModuleVersionsColumns.TABLE_NAME + " AS v"
+ " WHERE v." + ModuleVersionsColumns.MODULE_ID
@ -319,17 +319,17 @@ public final class RepoDb extends SQLiteOpenHelper {
}
public static void updateAllModulesLatestVersion() {
sDb.beginTransaction();
db.beginTransaction();
try {
String[] projection = new String[]{ModulesColumns.PKGNAME};
Cursor c = sDb.query(true, ModulesColumns.TABLE_NAME, projection, null, null, null, null, null, null);
Cursor c = db.query(true, ModulesColumns.TABLE_NAME, projection, null, null, null, null, null, null);
while (c.moveToNext()) {
updateModuleLatestVersion(c.getString(0));
}
c.close();
sDb.setTransactionSuccessful();
db.setTransactionSuccessful();
} finally {
sDb.endTransaction();
db.endTransaction();
}
}
@ -339,15 +339,15 @@ public final class RepoDb extends SQLiteOpenHelper {
values.put(InstalledModulesColumns.PKGNAME, installed.packageName);
values.put(InstalledModulesColumns.VERSION_CODE, installed.versionCode);
values.put(InstalledModulesColumns.VERSION_NAME, installed.versionName);
return sDb.insertOrThrow(InstalledModulesColumns.TABLE_NAME, null, values);
return db.insertOrThrow(InstalledModulesColumns.TABLE_NAME, null, values);
}
public static void deleteInstalledModule(String packageName) {
sDb.delete(InstalledModulesColumns.TABLE_NAME, InstalledModulesColumns.PKGNAME + " = ?", new String[]{packageName});
db.delete(InstalledModulesColumns.TABLE_NAME, InstalledModulesColumns.PKGNAME + " = ?", new String[]{packageName});
}
public static void deleteAllInstalledModules() {
sDb.delete(InstalledModulesColumns.TABLE_NAME, null, null);
db.delete(InstalledModulesColumns.TABLE_NAME, null, null);
}
public static Cursor queryModuleOverview(int sortingOrder,
@ -413,7 +413,7 @@ public final class RepoDb extends SQLiteOpenHelper {
sbOrder.append(OverviewColumns.PKGNAME);
// Query
Cursor c = sDb.query(
Cursor c = db.query(
ModulesColumns.TABLE_NAME + " AS m"
+ " LEFT JOIN " + ModuleVersionsColumns.TABLE_NAME + " AS v"
+ " ON v." + ModuleVersionsColumns._ID + " = m." + ModulesColumns.LATEST_VERSION
@ -439,7 +439,7 @@ public final class RepoDb extends SQLiteOpenHelper {
String[] projection = new String[]{InstalledModulesUpdatesColumns.LATEST_NAME};
String where = ModulesColumns.PKGNAME + (framework ? " = ?" : " != ?");
String[] whereArgs = new String[]{ModuleUtil.getInstance().getFrameworkPackageName()};
Cursor c = sDb.query(InstalledModulesUpdatesColumns.VIEW_NAME, projection, where, whereArgs, null, null, null, "1");
Cursor c = db.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));

View File

@ -33,7 +33,7 @@ public class RepoParser {
public final static String TAG = XposedApp.TAG;
private final static String NS = null;
private final XmlPullParser parser;
private RepoParserCallback mCallback;
private RepoParserCallback callback;
private boolean mRepoEventTriggered = false;
private RepoParser(InputStream is, RepoParserCallback callback) throws XmlPullParserException, IOException {
@ -41,7 +41,7 @@ public class RepoParser {
parser = factory.newPullParser();
parser.setInput(is, null);
parser.nextTag();
mCallback = callback;
this.callback = callback;
}
public static void parse(InputStream is, RepoParserCallback callback) throws XmlPullParserException, IOException {
@ -113,13 +113,13 @@ public class RepoParser {
triggerRepoEvent(repository);
Module module = readModule(repository);
if (module != null)
mCallback.onNewModule(module);
callback.onNewModule(module);
break;
case "remove-module":
triggerRepoEvent(repository);
String packageName = readRemoveModule();
if (packageName != null)
mCallback.onRemoveModule(packageName);
callback.onRemoveModule(packageName);
break;
default:
//skip(true);
@ -128,14 +128,14 @@ public class RepoParser {
}
}
mCallback.onCompleted(repository);
callback.onCompleted(repository);
}
private void triggerRepoEvent(Repository repository) {
if (mRepoEventTriggered)
return;
mCallback.onRepositoryMetadata(repository);
callback.onRepositoryMetadata(repository);
mRepoEventTriggered = true;
}

View File

@ -29,60 +29,6 @@ public class JSONUtils {
return sb.toString();
}
// private static String getLatestVersion() throws IOException {
// String site = getFileContent("http://dl-xda.xposed.info/framework/sdk" + Build.VERSION.SDK_INT + "/arm/");
//
// Pattern pattern = Pattern.compile("(href=\")([^?\"]*)\\.zip");
// Matcher matcher = pattern.matcher(site);
// String last = "";
// while (matcher.find()) {
// if (matcher.group().contains("test")) continue;
// last = matcher.group();
// }
// last = last.replace("href=\"", "");
// String[] file = last.split("-");
//
// return file[1].replace("v", "");
// }
//
// public static String listZip() {
// String latest;
// try {
// latest = getLatestVersion();
// } catch (IOException e) {
// // Got 404 response; no official Xposed zips available
// return "";
// }
//
// StringBuilder newJson = new StringBuilder(",\"" + Build.VERSION.SDK_INT + "\": [");
// String[] arch = new String[]{
// "arm",
// "arm64",
// "x86"
// };
//
// for (String a : arch) {
// newJson.append(installerToString(latest, a)).append(",");
// }
//
// newJson = new StringBuilder(newJson.substring(0, newJson.length() - 1));
// newJson.append("]");
//
// return newJson.toString();
// }
//
// private static String installerToString(String latest, String architecture) {
// String filename = "xposed-v" + latest + "-sdk" + Build.VERSION.SDK_INT + "-" + architecture;
//
// XposedZip installer = new XposedZip();
// installer.name = filename;
// installer.version = latest;
// installer.architecture = architecture;
// installer.link = "http://dl-xda.xposed.info/framework/sdk" + Build.VERSION.SDK_INT + "/" + architecture + "/" + filename + ".zip";
//
// return new Gson().toJson(installer);
// }
public class XposedJson {
public List<XposedTab> tabs;
public ApkRelease apk;

View File

@ -48,31 +48,6 @@ public class XposedTab implements Parcelable {
official = in.readByte() != 0;
}
// public String getNotice() {
// if (notice == null) return "";
// return notice.get(Integer.toString(Build.VERSION.SDK_INT));
// }
// public String getCompatibility() {
// if (compatibility == null) return "";
// return compatibility.get(Integer.toString(Build.VERSION.SDK_INT));
// }
//
// public String getIncompatibility() {
// if (incompatibility == null) return "";
// return incompatibility.get(Integer.toString(Build.VERSION.SDK_INT));
// }
// public String getSupport() {
// if (support == null) return "";
// return support.get(Integer.toString(Build.VERSION.SDK_INT));
// }
//
// public List<XposedZip> getInstallers() {
// if (support == null) return new ArrayList<>();
// return installers.get(Integer.toString(Build.VERSION.SDK_INT));
// }
@Override
public int describeContents() {
return 0;

View File

@ -26,7 +26,7 @@ public class XposedZip {
List<XposedZip> list;
public MyAdapter(Context context, List<XposedZip> objects) {
super(context, android.R.layout.simple_dropdown_item_1line, objects);
super(context, android.R.layout.simple_spinner_dropdown_item, objects);
this.context = context;
this.list = objects;
}
@ -57,7 +57,7 @@ public class XposedZip {
return row;
}
private class ItemHolder {
private static class ItemHolder {
TextView name;
}

View File

@ -6,67 +6,60 @@ import android.content.Intent;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import org.meowcat.edxposed.manager.R;
import org.meowcat.edxposed.manager.databinding.DownloadViewBinding;
import org.meowcat.edxposed.manager.util.DownloadsUtil;
import org.meowcat.edxposed.manager.util.DownloadsUtil.DownloadFinishedCallback;
import java.util.Objects;
public class DownloadView extends LinearLayout {
public static DownloadsUtil.DownloadInfo lastInfo = null;
private final Button btnDownload;
private final Button btnDownloadCancel;
private final Button btnInstall;
private final Button btnSave;
private final ProgressBar progressBar;
private final TextView txtInfo;
public Fragment fragment;
private DownloadsUtil.DownloadInfo mInfo = null;
private String mUrl = null;
private String mTitle = null;
private DownloadFinishedCallback mCallback = null;
private DownloadViewBinding binding;
private final Runnable refreshViewRunnable = new Runnable() {
@Override
public void run() {
if (mUrl == null) {
btnDownload.setVisibility(View.GONE);
btnSave.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);
binding.btnDownload.setVisibility(View.GONE);
binding.btnSave.setVisibility(View.GONE);
binding.btnDownloadCancel.setVisibility(View.GONE);
binding.btnInstall.setVisibility(View.GONE);
binding.progress.setVisibility(View.GONE);
binding.txtInfo.setVisibility(View.VISIBLE);
binding.txtInfo.setText(R.string.download_view_no_url);
} else if (mInfo == null) {
btnDownload.setVisibility(View.VISIBLE);
btnSave.setVisibility(View.VISIBLE);
btnDownloadCancel.setVisibility(View.GONE);
btnInstall.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
txtInfo.setVisibility(View.GONE);
binding.btnDownload.setVisibility(View.VISIBLE);
binding.btnSave.setVisibility(View.VISIBLE);
binding.btnDownloadCancel.setVisibility(View.GONE);
binding.btnInstall.setVisibility(View.GONE);
binding.progress.setVisibility(View.GONE);
binding.txtInfo.setVisibility(View.GONE);
} else {
switch (mInfo.status) {
case DownloadManager.STATUS_PENDING:
case DownloadManager.STATUS_PAUSED:
case DownloadManager.STATUS_RUNNING:
btnDownload.setVisibility(View.GONE);
btnSave.setVisibility(View.GONE);
btnDownloadCancel.setVisibility(View.VISIBLE);
btnInstall.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
txtInfo.setVisibility(View.VISIBLE);
binding.btnDownload.setVisibility(View.GONE);
binding.btnSave.setVisibility(View.GONE);
binding.btnDownloadCancel.setVisibility(View.VISIBLE);
binding.btnInstall.setVisibility(View.GONE);
binding.progress.setVisibility(View.VISIBLE);
binding.txtInfo.setVisibility(View.VISIBLE);
if (mInfo.totalSize <= 0 || mInfo.status != DownloadManager.STATUS_RUNNING) {
progressBar.setIndeterminate(true);
txtInfo.setText(R.string.download_view_waiting);
binding.progress.setIndeterminate(true);
binding.txtInfo.setText(R.string.download_view_waiting);
} else {
progressBar.setIndeterminate(false);
progressBar.setMax(mInfo.totalSize);
progressBar.setProgress(mInfo.bytesDownloaded);
txtInfo.setText(getContext().getString(
binding.progress.setIndeterminate(false);
binding.progress.setMax(mInfo.totalSize);
binding.progress.setProgress(mInfo.bytesDownloaded);
binding.txtInfo.setText(getContext().getString(
R.string.download_view_running,
mInfo.bytesDownloaded / 1024,
mInfo.totalSize / 1024));
@ -74,53 +67,45 @@ public class DownloadView extends LinearLayout {
break;
case DownloadManager.STATUS_FAILED:
btnDownload.setVisibility(View.VISIBLE);
btnSave.setVisibility(View.VISIBLE);
btnDownloadCancel.setVisibility(View.GONE);
btnInstall.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
txtInfo.setVisibility(View.VISIBLE);
txtInfo.setText(getContext().getString(
binding.btnDownload.setVisibility(View.VISIBLE);
binding.btnSave.setVisibility(View.VISIBLE);
binding.btnDownloadCancel.setVisibility(View.GONE);
binding.btnInstall.setVisibility(View.GONE);
binding.progress.setVisibility(View.GONE);
binding.txtInfo.setVisibility(View.VISIBLE);
binding.txtInfo.setText(getContext().getString(
R.string.download_view_failed, mInfo.reason));
break;
case DownloadManager.STATUS_SUCCESSFUL:
btnDownload.setVisibility(View.GONE);
btnSave.setVisibility(View.VISIBLE);
btnDownloadCancel.setVisibility(View.GONE);
btnInstall.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
txtInfo.setVisibility(View.VISIBLE);
txtInfo.setText(R.string.download_view_successful);
binding.btnDownload.setVisibility(View.GONE);
binding.btnSave.setVisibility(View.VISIBLE);
binding.btnDownloadCancel.setVisibility(View.GONE);
binding.btnInstall.setVisibility(View.VISIBLE);
binding.progress.setVisibility(View.GONE);
binding.txtInfo.setVisibility(View.VISIBLE);
binding.txtInfo.setText(R.string.download_view_successful);
break;
}
}
}
};
private String mTitle = null;
private DownloadFinishedCallback mCallback = null;
public DownloadView(Context context, final AttributeSet attrs) {
super(context, attrs);
setFocusable(false);
setOrientation(LinearLayout.VERTICAL);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Objects.requireNonNull(inflater).inflate(R.layout.download_view, this, true);
binding = DownloadViewBinding.inflate(LayoutInflater.from(context), this);
btnDownload = findViewById(R.id.btnDownload);
btnDownloadCancel = findViewById(R.id.btnDownloadCancel);
btnInstall = findViewById(R.id.btnInstall);
btnSave = findViewById(R.id.save);
btnDownload.setOnClickListener(v -> {
binding.btnDownload.setOnClickListener(v -> {
mInfo = DownloadsUtil.addModule(getContext(), mTitle, mUrl, mCallback);
refreshViewFromUiThread();
if (mInfo != null)
new DownloadMonitor().start();
});
btnSave.setOnClickListener(v -> {
binding.btnSave.setOnClickListener(v -> {
lastInfo = mInfo;
mInfo = DownloadsUtil.addModule(getContext(), mTitle, mUrl, (context1, info) -> {
Intent exportIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
@ -134,7 +119,7 @@ public class DownloadView extends LinearLayout {
new DownloadMonitor().start();
});
btnDownloadCancel.setOnClickListener(v -> {
binding.btnDownloadCancel.setOnClickListener(v -> {
if (mInfo == null)
return;
@ -142,16 +127,13 @@ public class DownloadView extends LinearLayout {
// UI update will happen automatically by the DownloadMonitor
});
btnInstall.setOnClickListener(v -> {
binding.btnInstall.setOnClickListener(v -> {
if (mCallback == null)
return;
mCallback.onDownloadFinished(getContext(), mInfo);
});
progressBar = findViewById(R.id.progress);
txtInfo = findViewById(R.id.txtInfo);
refreshViewFromUiThread();
}

View File

@ -6,6 +6,7 @@ import android.util.AttributeSet;
import com.takisoft.preferencex.SimpleMenuPreference;
@SuppressWarnings("unused")
public class IntegerListPreference extends SimpleMenuPreference {
public IntegerListPreference(Context context) {
super(context);
@ -15,7 +16,7 @@ public class IntegerListPreference extends SimpleMenuPreference {
super(context, attrs);
}
public static int getIntValue(String value) {
private static int getIntValue(String value) {
if (value == null)
return 0;

View File

@ -8,16 +8,20 @@
android:clipChildren="false"
android:clipToPadding="false">
<include layout="@layout/appbar_layout" />
<include
android:id="@+id/appbar"
layout="@layout/appbar_layout" />
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:ignore="UseCompoundDrawables,ContentDescription">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -7,7 +7,9 @@
android:clipChildren="false"
android:clipToPadding="false">
<include layout="@layout/appbar_layout" />
<include
android:id="@+id/appbar"
layout="@layout/appbar_layout" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
@ -21,7 +23,9 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -7,7 +7,9 @@
android:clipChildren="false"
android:clipToPadding="false">
<include layout="@layout/appbar_layout" />
<include
android:id="@+id/appbar"
layout="@layout/appbar_layout" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"

View File

@ -41,6 +41,7 @@
</com.google.android.material.appbar.AppBarLayout>
<HorizontalScrollView
android:id="@+id/horizontalScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"

View File

@ -53,7 +53,7 @@
</RelativeLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/activity_main_status"
android:id="@+id/status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
@ -73,7 +73,7 @@
android:paddingBottom="20dp">
<ImageView
android:id="@+id/activity_main_status_icon"
android:id="@+id/status_icon"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_centerVertical="true"
@ -82,21 +82,21 @@
app:srcCompat="@drawable/ic_check_circle" />
<TextView
android:id="@+id/activity_main_status_title"
android:id="@+id/status_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_toEndOf="@id/activity_main_status_icon"
android:layout_toEndOf="@id/status_icon"
android:text="@string/Activated"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/activity_main_status_summary"
android:id="@+id/status_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/activity_main_status_title"
android:layout_alignStart="@id/activity_main_status_title"
android:layout_below="@id/status_title"
android:layout_alignStart="@id/status_title"
android:layout_marginTop="5dp"
android:text="@string/ActivatedDetail"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
@ -105,7 +105,7 @@
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/activity_main_modules"
android:id="@+id/modules"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
@ -124,7 +124,7 @@
android:paddingBottom="16dp">
<ImageView
android:id="@+id/activity_main_modules_icon"
android:id="@+id/modules_icon"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_centerVertical="true"
@ -132,20 +132,20 @@
app:srcCompat="@drawable/ic_apps" />
<TextView
android:id="@+id/activity_main_modules_title"
android:id="@+id/modules_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_toEndOf="@id/activity_main_modules_icon"
android:layout_toEndOf="@id/modules_icon"
android:text="@string/Modules"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/activity_main_modules_summary"
android:id="@+id/modules_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/activity_main_modules_title"
android:layout_alignStart="@id/activity_main_modules_title"
android:layout_below="@id/modules_title"
android:layout_alignStart="@id/modules_title"
android:layout_marginTop="2dp"
android:text="@string/ModulesDetail"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
@ -154,7 +154,7 @@
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/activity_main_downloads"
android:id="@+id/downloads"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
@ -173,7 +173,7 @@
android:paddingBottom="16dp">
<ImageView
android:id="@+id/activity_main_downloads_icon"
android:id="@+id/downloads_icon"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_centerVertical="true"
@ -181,20 +181,20 @@
app:srcCompat="@drawable/ic_get_app" />
<TextView
android:id="@+id/activity_main_downloads_title"
android:id="@+id/downloads_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_toEndOf="@id/activity_main_downloads_icon"
android:layout_toEndOf="@id/downloads_icon"
android:text="@string/Downloads"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/activity_main_download_summary"
android:id="@+id/download_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/activity_main_downloads_title"
android:layout_alignStart="@id/activity_main_downloads_title"
android:layout_below="@id/downloads_title"
android:layout_alignStart="@id/downloads_title"
android:layout_marginTop="2dp"
android:text="@string/ModuleUpgradable"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
@ -203,7 +203,7 @@
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:id="@+id/activity_main_apps"
android:id="@+id/apps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
@ -229,7 +229,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/activity_main_logs"
android:id="@+id/logs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
@ -255,7 +255,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/activity_main_settings"
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
@ -281,7 +281,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/activity_main_about"
android:id="@+id/about"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"

View File

@ -7,7 +7,9 @@
android:clipChildren="false"
android:clipToPadding="false">
<include layout="@layout/appbar_layout" />
<include
android:id="@+id/appbar"
layout="@layout/appbar_layout" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"

View File

@ -7,7 +7,9 @@
android:clipChildren="false"
android:clipToPadding="false">
<include layout="@layout/appbar_layout" />
<include
android:id="@+id/appbar"
layout="@layout/appbar_layout" />
<FrameLayout
android:id="@+id/container"

View File

@ -23,7 +23,7 @@
android:theme="@style/Widget.AppCompat.Button.Colored" />
<com.google.android.material.button.MaterialButton
android:id="@+id/save"
android:id="@+id/btnSave"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -3,9 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp">
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
@ -203,7 +201,7 @@
android:paddingBottom="8dp">
<TextView
android:id="@+id/ic_manufacturer"
android:id="@+id/manufacturer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />