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' apply plugin: 'com.google.android.gms.oss-licenses-plugin'
android { android {
viewBinding {
enabled = true
}
compileSdkVersion 28 compileSdkVersion 28
buildToolsVersion "29.0.3" buildToolsVersion "29.0.3"
defaultConfig { defaultConfig {

View File

@ -6,41 +6,30 @@ import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.view.View; import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; import com.google.android.gms.oss.licenses.OssLicensesMenuActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.meowcat.edxposed.manager.databinding.ActivityAboutBinding;
import org.meowcat.edxposed.manager.util.NavUtil; import org.meowcat.edxposed.manager.util.NavUtil;
public class AboutActivity extends BaseActivity { public class AboutActivity extends BaseActivity {
ActivityAboutBinding binding;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about); binding = ActivityAboutBinding.inflate(getLayoutInflater());
Toolbar toolbar = findViewById(R.id.toolbar); setContentView(binding.getRoot());
setSupportActionBar(toolbar); setSupportActionBar(binding.appbar.toolbar);
toolbar.setNavigationOnClickListener(view -> finish()); binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar(); ActionBar bar = getSupportActionBar();
if (bar != null) { if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true); bar.setDisplayHomeAsUpEnabled(true);
} }
setupWindowInsets(); setupWindowInsets(binding.snackbar, binding.nestedScrollView);
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);
String packageName = getPackageName(); String packageName = getPackageName();
String translator = getResources().getString(R.string.translator); String translator = getResources().getString(R.string.translator);
@ -50,9 +39,9 @@ public class AboutActivity extends BaseActivity {
final String changes = prefs.getString("changelog", null); final String changes = prefs.getString("changelog", null);
if (changes == null) { if (changes == null) {
changelogView.setVisibility(View.GONE); binding.changelogView.setVisibility(View.GONE);
} else { } else {
changelogView.setOnClickListener(v1 -> new MaterialAlertDialogBuilder(this) binding.changelogView.setOnClickListener(v1 -> new MaterialAlertDialogBuilder(this)
.setTitle(R.string.changes) .setTitle(R.string.changes)
.setMessage(Html.fromHtml(changes)) .setMessage(Html.fromHtml(changes))
.setPositiveButton(android.R.string.ok, null).show()); .setPositiveButton(android.R.string.ok, null).show());
@ -60,25 +49,25 @@ public class AboutActivity extends BaseActivity {
try { try {
String version = getPackageManager().getPackageInfo(packageName, 0).versionName; String version = getPackageManager().getPackageInfo(packageName, 0).versionName;
((TextView) findViewById(R.id.app_version)).setText(version); binding.appVersion.setText(version);
} catch (PackageManager.NameNotFoundException ignored) { } 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))); getString(R.string.module_support)));
setupView(installerSupportView, R.string.support_material_xda); setupView(binding.installerSupportView, R.string.support_material_xda);
setupView(faqView, R.string.support_faq_url); setupView(binding.faqView, R.string.support_faq_url);
setupView(tgGroupView, R.string.group_telegram_link); setupView(binding.tgGroupView, R.string.group_telegram_link);
setupView(qqGroupView, R.string.group_qq_link); setupView(binding.qqGroupView, R.string.group_qq_link);
setupView(donateView, R.string.support_donate_url); setupView(binding.donateView, R.string.support_donate_url);
setupView(sourceCodeView, R.string.about_source); setupView(binding.sourceCodeView, R.string.about_source);
setupView(tgChannelView, R.string.group_telegram_channel_link); setupView(binding.tgChannelView, R.string.group_telegram_channel_link);
if (translator.isEmpty()) { 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))); 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; return (configuration.uiMode & Configuration.UI_MODE_NIGHT_YES) > 0;
} }
protected void setupWindowInsets() { protected void setupWindowInsets(View rootView, View secondView) {
View rootView = findViewById(R.id.snackbar);
rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, insets) -> { 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; return insets;
}); });
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,12 +8,14 @@ import android.util.Pair;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment; 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.Module;
import org.meowcat.edxposed.manager.repo.RepoParser; import org.meowcat.edxposed.manager.repo.RepoParser;
import org.meowcat.edxposed.manager.util.NavUtil; import org.meowcat.edxposed.manager.util.NavUtil;
@ -32,50 +34,47 @@ public class DownloadDetailsFragment extends Fragment {
if (module == null) { if (module == null) {
return 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()) 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 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.description != null) {
if (module.descriptionIsHtml) { if (module.descriptionIsHtml) {
description.setText(RepoParser.parseSimpleHtml(getActivity(), module.description, description)); binding.downloadDescription.setText(RepoParser.parseSimpleHtml(getActivity(), module.description, binding.downloadDescription));
description.setTransformationMethod(new LinkTransformationMethod((AppCompatActivity) getActivity())); binding.downloadDescription.setTransformationMethod(new LinkTransformationMethod((AppCompatActivity) getActivity()));
description.setMovementMethod(LinkMovementMethod.getInstance()); binding.downloadDescription.setMovementMethod(LinkMovementMethod.getInstance());
} else { } else {
description.setText(module.description); binding.downloadDescription.setText(module.description);
} }
description.setTextIsSelectable(true); binding.downloadDescription.setTextIsSelectable(true);
} else { } 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) { for (Pair<String, String> moreInfoEntry : module.moreInfo) {
View moreInfoView = inflater.inflate(R.layout.download_moreinfo, moreInfoContainer, false); DownloadMoreinfoBinding moreinfoBinding = DownloadMoreinfoBinding.inflate(inflater, binding.downloadMoreinfoContainer, false);
TextView txtTitle = moreInfoView.findViewById(android.R.id.title);
TextView txtValue = moreInfoView.findViewById(android.R.id.message);
txtTitle.setText(moreInfoEntry.first + ":"); moreinfoBinding.title.setText(moreInfoEntry.first + ":");
txtValue.setText(moreInfoEntry.second); moreinfoBinding.message.setText(moreInfoEntry.second);
final Uri link = NavUtil.parseURL(moreInfoEntry.second); final Uri link = NavUtil.parseURL(moreInfoEntry.second);
if (link != null) { if (link != null) {
txtValue.setTextColor(txtValue.getLinkTextColors()); moreinfoBinding.message.setTextColor(moreinfoBinding.message.getLinkTextColors());
moreInfoView.setOnClickListener(v -> NavUtil.startURL((AppCompatActivity) getActivity(), link)); 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.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import com.takisoft.preferencex.PreferenceFragmentCompat; import com.takisoft.preferencex.PreferenceFragmentCompat;
@ -16,7 +17,6 @@ import java.util.Map;
public class DownloadDetailsSettingsFragment extends PreferenceFragmentCompat { public class DownloadDetailsSettingsFragment extends PreferenceFragmentCompat {
@Override @Override
public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) { public void onCreatePreferencesFix(Bundle savedInstanceState, String rootKey) {
DownloadDetailsActivity mActivity = (DownloadDetailsActivity) getActivity(); DownloadDetailsActivity mActivity = (DownloadDetailsActivity) getActivity();
@ -48,11 +48,13 @@ public class DownloadDetailsSettingsFragment extends PreferenceFragmentCompat {
editor.putBoolean("no_global", false).apply(); editor.putBoolean("no_global", false).apply();
} }
findPreference("release_type").setOnPreferenceChangeListener( Preference releaseType = findPreference("release_type");
(preference, newValue) -> { if (releaseType != null) {
releaseType.setOnPreferenceChangeListener((preference, newValue) -> {
RepoLoader.getInstance().setReleaseTypeLocal(packageName, (String) newValue); RepoLoader.getInstance().setReleaseTypeLocal(packageName, (String) newValue);
return true; return true;
}); });
} }
}
} }

View File

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

View File

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

View File

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

View File

@ -3,72 +3,66 @@ package org.meowcat.edxposed.manager;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; 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.PopupMenu;
import androidx.appcompat.widget.TooltipCompat; 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.ModuleUtil;
import org.meowcat.edxposed.manager.util.RepoLoader; import org.meowcat.edxposed.manager.util.RepoLoader;
public class MainActivity extends BaseActivity implements RepoLoader.RepoListener, ModuleUtil.ModuleListener { public class MainActivity extends BaseActivity implements RepoLoader.RepoListener, ModuleUtil.ModuleListener {
ActivityMainBinding binding;
private RepoLoader mRepoLoader; private RepoLoader mRepoLoader;
@SuppressLint("PrivateResource") @SuppressLint("PrivateResource")
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
mRepoLoader = RepoLoader.getInstance(); mRepoLoader = RepoLoader.getInstance();
ModuleUtil.getInstance().addListener(this); ModuleUtil.getInstance().addListener(this);
mRepoLoader.addListener(this, false); mRepoLoader.addListener(this, false);
findViewById(R.id.activity_main_modules).setOnClickListener(v -> { binding.modules.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), ModulesActivity.class); intent.setClass(getApplicationContext(), ModulesActivity.class);
startActivity(intent); startActivity(intent);
}); });
findViewById(R.id.activity_main_downloads).setOnClickListener(v -> { binding.downloads.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), DownloadActivity.class); intent.setClass(getApplicationContext(), DownloadActivity.class);
startActivity(intent); startActivity(intent);
}); });
findViewById(R.id.activity_main_apps).setOnClickListener(v -> { binding.apps.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), BlackListActivity.class); intent.setClass(getApplicationContext(), BlackListActivity.class);
startActivity(intent); startActivity(intent);
}); });
findViewById(R.id.activity_main_status).setOnClickListener(v -> { binding.status.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), EdDownloadActivity.class); intent.setClass(getApplicationContext(), EdDownloadActivity.class);
startActivity(intent); startActivity(intent);
}); });
findViewById(R.id.activity_main_settings).setOnClickListener(v -> { binding.settings.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), SettingsActivity.class); intent.setClass(getApplicationContext(), SettingsActivity.class);
startActivity(intent); startActivity(intent);
}); });
findViewById(R.id.activity_main_logs).setOnClickListener(v -> { binding.logs.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), LogsActivity.class); intent.setClass(getApplicationContext(), LogsActivity.class);
startActivity(intent); startActivity(intent);
}); });
findViewById(R.id.activity_main_about).setOnClickListener(v -> { binding.about.setOnClickListener(v -> {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(getApplicationContext(), AboutActivity.class); intent.setClass(getApplicationContext(), AboutActivity.class);
startActivity(intent); startActivity(intent);
}); });
ImageView menu = findViewById(R.id.menu_more); TooltipCompat.setTooltipText(binding.menuMore, getString(androidx.appcompat.R.string.abc_action_menu_overflow_description));
TooltipCompat.setTooltipText(menu, getString(androidx.appcompat.R.string.abc_action_menu_overflow_description)); binding.menuMore.setOnClickListener(v -> {
menu.setOnClickListener(v -> { PopupMenu appMenu = new PopupMenu(MainActivity.this, binding.menuMore);
PopupMenu appMenu = new PopupMenu(MainActivity.this, menu);
appMenu.inflate(R.menu.menu_installer); appMenu.inflate(R.menu.menu_installer);
appMenu.setOnMenuItemClickListener(this::onOptionsItemSelected); appMenu.setOnMenuItemClickListener(this::onOptionsItemSelected);
appMenu.show(); appMenu.show();
@ -79,29 +73,25 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
} catch (NullPointerException e) { } catch (NullPointerException e) {
installedXposedVersion = null; 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) { if (installedXposedVersion != null) {
int installedXposedVersionInt = extractIntPart(installedXposedVersion); int installedXposedVersionInt = extractIntPart(installedXposedVersion);
if (installedXposedVersionInt == XposedApp.getXposedVersion()) { if (installedXposedVersionInt == XposedApp.getXposedVersion()) {
String installedXposedVersionStr = installedXposedVersionInt + ".0"; String installedXposedVersionStr = installedXposedVersionInt + ".0";
title.setText(R.string.Activated); binding.statusTitle.setText(R.string.Activated);
details.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", "")); binding.statusSummary.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
cardView.setCardBackgroundColor(getResources().getColor(R.color.download_status_update_available)); binding.status.setCardBackgroundColor(getResources().getColor(R.color.download_status_update_available));
icon.setImageDrawable(getDrawable(R.drawable.ic_check_circle)); binding.statusIcon.setImageDrawable(getDrawable(R.drawable.ic_check_circle));
} else { } else {
title.setText(R.string.Inactivate); binding.statusTitle.setText(R.string.Inactivate);
details.setText(R.string.installed_lollipop_inactive); binding.statusSummary.setText(R.string.installed_lollipop_inactive);
cardView.setCardBackgroundColor(getResources().getColor(R.color.amber_500)); binding.status.setCardBackgroundColor(getResources().getColor(R.color.amber_500));
icon.setImageDrawable(getDrawable(R.drawable.ic_warning)); binding.statusIcon.setImageDrawable(getDrawable(R.drawable.ic_warning));
} }
} else { } else {
title.setText(R.string.Install); binding.statusTitle.setText(R.string.Install);
details.setText(R.string.InstallDetail); binding.statusSummary.setText(R.string.InstallDetail);
cardView.setCardBackgroundColor(getResources().getColor(R.color.colorPrimary)); binding.status.setCardBackgroundColor(getResources().getColor(R.color.colorPrimary));
icon.setImageDrawable(getDrawable(R.drawable.ic_error)); binding.statusIcon.setImageDrawable(getDrawable(R.drawable.ic_error));
} }
notifyDataSetChanged(); notifyDataSetChanged();
} }
@ -118,45 +108,19 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
return result; 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() { private void notifyDataSetChanged() {
runOnUiThread(() -> { runOnUiThread(() -> {
String frameworkUpdateVersion = mRepoLoader.getFrameworkUpdateVersion(); String frameworkUpdateVersion = mRepoLoader.getFrameworkUpdateVersion();
boolean moduleUpdateAvailable = mRepoLoader.hasModuleUpdates(); boolean moduleUpdateAvailable = mRepoLoader.hasModuleUpdates();
ModuleUtil.getInstance().getEnabledModules().size(); ModuleUtil.getInstance().getEnabledModules().size();
TextView description = findViewById(R.id.activity_main_modules_summary); binding.modulesSummary.setText(String.format(getString(R.string.ModulesDetail), ModuleUtil.getInstance().getEnabledModules().size()));
description.setText(String.format(getString(R.string.ModulesDetail), ModuleUtil.getInstance().getEnabledModules().size()));
if (frameworkUpdateVersion != null) { if (frameworkUpdateVersion != null) {
description = findViewById(R.id.activity_main_status_summary); binding.statusSummary.setText(String.format(getString(R.string.welcome_framework_update_available), frameworkUpdateVersion));
description.setText(String.format(getString(R.string.welcome_framework_update_available), frameworkUpdateVersion));
} }
description = findViewById(R.id.activity_main_download_summary);
if (moduleUpdateAvailable) { if (moduleUpdateAvailable) {
description.setText(R.string.modules_updates_available); binding.downloadSummary.setText(R.string.modules_updates_available);
} else { } 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.app.ActionBar;
import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.snackbar.Snackbar; 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.Module;
import org.meowcat.edxposed.manager.repo.ModuleVersion; import org.meowcat.edxposed.manager.repo.ModuleVersion;
import org.meowcat.edxposed.manager.repo.ReleaseType; 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 class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleListener {
public static final String SETTINGS_CATEGORY = "de.robv.android.xposed.category.MODULE_SETTINGS"; public static final String SETTINGS_CATEGORY = "de.robv.android.xposed.category.MODULE_SETTINGS";
ActivityModulesBinding binding;
private int installedXposedVersion; private int installedXposedVersion;
private ApplicationFilter filter; private ApplicationFilter filter;
private SearchView mSearchView; private SearchView searchView;
private SearchView.OnQueryTextListener mSearchListener; private SearchView.OnQueryTextListener mSearchListener;
private PackageManager mPm; private PackageManager pm;
private DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); private DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
private ModuleUtil mModuleUtil; private ModuleUtil moduleUtil;
private ModuleAdapter mAdapter = null; private ModuleAdapter adapter = null;
private RecyclerView mListView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private Runnable reloadModules = new Runnable() { private Runnable reloadModules = new Runnable() {
public void run() { public void run() {
String queryStr = mSearchView != null ? mSearchView.getQuery().toString() : ""; String queryStr = searchView != null ? searchView.getQuery().toString() : "";
Collection<ModuleUtil.InstalledModule> showList; Collection<ModuleUtil.InstalledModule> showList;
Collection<ModuleUtil.InstalledModule> fullList = mModuleUtil.getModules().values(); Collection<ModuleUtil.InstalledModule> fullList = moduleUtil.getModules().values();
if (queryStr.length() == 0) { if (queryStr.length() == 0) {
showList = fullList; showList = fullList;
} else { } else {
showList = new ArrayList<>(); showList = new ArrayList<>();
String filter = queryStr.toLowerCase(); String filter = queryStr.toLowerCase();
for (ModuleUtil.InstalledModule info : fullList) { 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)) { || lowercaseContains(info.packageName, filter)) {
showList.add(info); showList.add(info);
} }
} }
} }
mAdapter.addAll(showList); adapter.addAll(showList);
mAdapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
mModuleUtil.updateModulesList(false); moduleUtil.updateModulesList(false);
mSwipeRefreshLayout.setRefreshing(false); binding.swipeRefreshLayout.setRefreshing(false);
} }
}; };
private String selectedPackageName; private String selectedPackageName;
@ -102,36 +100,33 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_modules); binding = ActivityModulesBinding.inflate(getLayoutInflater());
Toolbar toolbar = findViewById(R.id.toolbar); setContentView(binding.getRoot());
setSupportActionBar(toolbar); setSupportActionBar(binding.appbar.toolbar);
toolbar.setNavigationOnClickListener(view -> finish()); binding.appbar.toolbar.setNavigationOnClickListener(view -> finish());
ActionBar bar = getSupportActionBar(); ActionBar bar = getSupportActionBar();
if (bar != null) { if (bar != null) {
bar.setDisplayHomeAsUpEnabled(true); bar.setDisplayHomeAsUpEnabled(true);
} }
setupWindowInsets(); setupWindowInsets(binding.snackbar, binding.recyclerView);
filter = new ApplicationFilter(); filter = new ApplicationFilter();
mModuleUtil = ModuleUtil.getInstance(); moduleUtil = ModuleUtil.getInstance();
mPm = getPackageManager(); pm = getPackageManager();
installedXposedVersion = XposedApp.getXposedVersion(); installedXposedVersion = XposedApp.getXposedVersion();
if (installedXposedVersion <= 0) { 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 intent = new Intent();
intent.setClass(ModulesActivity.this, SettingsActivity.class); intent.setClass(ModulesActivity.this, SettingsActivity.class);
startActivity(intent); startActivity(intent);
}).show(); }).show();
} }
mAdapter = new ModuleAdapter(); adapter = new ModuleAdapter();
mModuleUtil.addListener(this); moduleUtil.addListener(this);
mListView = findViewById(R.id.recyclerView); binding.recyclerView.setAdapter(adapter);
mListView.setAdapter(mAdapter); binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mListView.setLayoutManager(new LinearLayoutManager(this)); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mListView.getContext(), binding.recyclerView.addItemDecoration(dividerItemDecoration);
DividerItemDecoration.VERTICAL); binding.swipeRefreshLayout.setOnRefreshListener(() -> reloadModules.run());
mListView.addItemDecoration(dividerItemDecoration);
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(() -> reloadModules.run());
reloadModules.run(); reloadModules.run();
mSearchListener = new SearchView.OnQueryTextListener() { mSearchListener = new SearchView.OnQueryTextListener() {
@Override @Override
@ -152,8 +147,8 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_modules, menu); getMenuInflater().inflate(R.menu.menu_modules, menu);
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
mSearchView.setOnQueryTextListener(mSearchListener); searchView.setOnQueryTextListener(mSearchListener);
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@ -180,7 +175,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
os.close(); os.close();
} }
} catch (Exception e) { } 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(); os.close();
} }
} catch (Exception e) { } 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()) { switch (item.getItemId()) {
case R.id.export_enabled_modules: case R.id.export_enabled_modules:
if (ModuleUtil.getInstance().getEnabledModules().isEmpty()) { 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; return false;
} }
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); 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(); Map<String, ModuleUtil.InstalledModule> installedModules = ModuleUtil.getInstance().getModules();
if (installedModules.isEmpty()) { 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; return false;
} }
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
@ -271,7 +266,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
Module m = repoLoader.getModule(line); Module m = repoLoader.getModule(line);
if (m == null) { 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 { } else {
list.add(m); list.add(m);
} }
@ -279,11 +274,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
br.close(); br.close();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); 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) { for (final Module m : list) {
if (mModuleUtil.getModule(m.packageName) != null) { if (moduleUtil.getModule(m.packageName) != null) {
continue; continue;
} }
ModuleVersion mv = null; ModuleVersion mv = null;
@ -307,20 +302,20 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
mModuleUtil.removeListener(this); moduleUtil.removeListener(this);
mListView.setAdapter(null); binding.recyclerView.setAdapter(null);
mAdapter = null; adapter = null;
} }
@Override @Override
public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, ModuleUtil.InstalledModule module) { public void onSingleInstalledModuleReloaded(ModuleUtil moduleUtil, String packageName, ModuleUtil.InstalledModule module) {
mModuleUtil.updateModulesList(false); moduleUtil.updateModulesList(false);
runOnUiThread(reloadModules); runOnUiThread(reloadModules);
} }
@Override @Override
public void onInstalledModulesReloaded(ModuleUtil moduleUtil) { public void onInstalledModulesReloaded(ModuleUtil moduleUtil) {
mModuleUtil.updateModulesList(false); moduleUtil.updateModulesList(false);
runOnUiThread(reloadModules); runOnUiThread(reloadModules);
} }
@ -340,7 +335,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
if (launchIntent != null) { if (launchIntent != null) {
startActivity(launchIntent); startActivity(launchIntent);
} else { } 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; return true;
@ -404,10 +399,10 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (mSearchView.isIconified()) { if (searchView.isIconified()) {
super.onBackPressed(); super.onBackPressed();
} else { } else {
mSearchView.setIconified(true); searchView.setIconified(true);
} }
} }
@ -485,13 +480,13 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
SwitchCompat mSwitch = holder.mSwitch; SwitchCompat mSwitch = holder.mSwitch;
mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
String packageName = item.packageName; String packageName = item.packageName;
boolean changed = mModuleUtil.isModuleEnabled(packageName) ^ isChecked; boolean changed = moduleUtil.isModuleEnabled(packageName) ^ isChecked;
if (changed) { if (changed) {
mModuleUtil.setModuleEnabled(packageName, isChecked); moduleUtil.setModuleEnabled(packageName, isChecked);
mModuleUtil.updateModulesList(true); moduleUtil.updateModulesList(true);
} }
}); });
mSwitch.setChecked(mModuleUtil.isModuleEnabled(item.packageName)); mSwitch.setChecked(moduleUtil.isModuleEnabled(item.packageName));
TextView warningText = holder.warningText; TextView warningText = holder.warningText;
if (item.minVersion == 0) { if (item.minVersion == 0) {

View File

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

View File

@ -11,14 +11,15 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.meowcat.edxposed.manager.databinding.StatusInstallerBinding;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
@ -27,28 +28,25 @@ import java.lang.reflect.Method;
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
public class StatusInstallerFragment extends Fragment { public class StatusInstallerFragment extends Fragment {
private static StatusInstallerBinding binding;
private static String updateLink;
private static AppCompatActivity sActivity; static void setUpdate(final String link, final String changelog, Context context) {
private static String mUpdateLink; updateLink = link;
private static View mUpdateView;
private static View mUpdateButton;
static void setUpdate(final String link, final String changelog, Context mContext) { binding.updateView.setVisibility(View.VISIBLE);
mUpdateLink = link; binding.clickToUpdate.setVisibility(View.VISIBLE);
binding.clickToUpdate.setOnClickListener(v -> new MaterialAlertDialogBuilder(context)
mUpdateView.setVisibility(View.VISIBLE);
mUpdateButton.setVisibility(View.VISIBLE);
mUpdateButton.setOnClickListener(v -> new MaterialAlertDialogBuilder(sActivity)
.setTitle(R.string.changes) .setTitle(R.string.changes)
.setMessage(Html.fromHtml(changelog)) .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()); .setNegativeButton(R.string.later, null).show());
} }
private static void update(Context mContext) { private static void update(Context context) {
Uri uri = Uri.parse(mUpdateLink); Uri uri = Uri.parse(updateLink);
Intent intent = new Intent(Intent.ACTION_VIEW, uri); Intent intent = new Intent(Intent.ACTION_VIEW, uri);
mContext.startActivity(intent); context.startActivity(intent);
} }
private static String getCompleteArch() { private static String getCompleteArch() {
@ -73,6 +71,7 @@ public class StatusInstallerFragment extends Fragment {
return info + " (" + getArch() + ")"; return info + " (" + getArch() + ")";
} }
@SuppressWarnings("deprecation")
private static String getArch() { private static String getArch() {
if (Build.CPU_ABI.equals("arm64-v8a")) { if (Build.CPU_ABI.equals("arm64-v8a")) {
return "arm64"; 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") @SuppressLint("WorldReadableFiles")
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.status_installer, container, false); binding = StatusInstallerBinding.inflate(inflater, container, false);
mUpdateView = v.findViewById(R.id.updateView);
mUpdateButton = v.findViewById(R.id.click_to_update);
String installedXposedVersion; String installedXposedVersion;
try { try {
@ -113,31 +102,24 @@ public class StatusInstallerFragment extends Fragment {
installedXposedVersion = null; 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 + ")"; String mAppVer = "v" + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")";
manager.setText(mAppVer); binding.manager.setText(mAppVer);
if (installedXposedVersion != null) { if (installedXposedVersion != null) {
int installedXposedVersionInt = extractIntPart(installedXposedVersion); int installedXposedVersionInt = extractIntPart(installedXposedVersion);
String installedXposedVersionStr = installedXposedVersionInt + ".0"; String installedXposedVersionStr = installedXposedVersionInt + ".0";
api.setText(installedXposedVersionStr); binding.api.setText(installedXposedVersionStr);
framework.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", "")); binding.framework.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
} }
androidSdk.setText(getString(R.string.android_sdk, getAndroidVersion(), Build.VERSION.RELEASE, Build.VERSION.SDK_INT)); binding.androidVersion.setText(getString(R.string.android_sdk, getAndroidVersion(), Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
manufacturer.setText(getUIFramework()); binding.manufacturer.setText(getUIFramework());
cpu.setText(getCompleteArch()); binding.cpu.setText(getCompleteArch());
determineVerifiedBootState(v); determineVerifiedBootState(binding);
return v; return binding.getRoot();
} }
private void determineVerifiedBootState(View v) { private void determineVerifiedBootState(StatusInstallerBinding binding) {
try { try {
@SuppressLint("PrivateApi") Class<?> c = Class.forName("android.os.SystemProperties"); @SuppressLint("PrivateApi") Class<?> c = Class.forName("android.os.SystemProperties");
Method m = c.getDeclaredMethod("get", String.class, String.class); Method m = c.getDeclaredMethod("get", String.class, String.class);
@ -150,17 +132,16 @@ public class StatusInstallerFragment extends Fragment {
boolean verified = !propSystemVerified.equals("0"); boolean verified = !propSystemVerified.equals("0");
boolean detected = !propState.isEmpty() || fileDmVerityModule.exists(); boolean detected = !propState.isEmpty() || fileDmVerityModule.exists();
TextView tv = v.findViewById(R.id.dmverity);
if (verified) { if (verified) {
tv.setText(R.string.verified_boot_active); binding.dmverity.setText(R.string.verified_boot_active);
tv.setTextColor(getResources().getColor(R.color.warning)); binding.dmverity.setTextColor(getResources().getColor(R.color.warning));
} else if (detected) { } else if (detected) {
tv.setText(R.string.verified_boot_deactivated); binding.dmverity.setText(R.string.verified_boot_deactivated);
v.findViewById(R.id.dmverity_explanation).setVisibility(View.GONE); binding.dmverityExplanation.setVisibility(View.GONE);
} else { } else {
tv.setText(R.string.verified_boot_none); binding.dmverity.setText(R.string.verified_boot_none);
tv.setTextColor(getResources().getColor(R.color.warning)); binding.dmverity.setTextColor(getResources().getColor(R.color.warning));
v.findViewById(R.id.dmverity_explanation).setVisibility(View.GONE); binding.dmverityExplanation.setVisibility(View.GONE);
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(XposedApp.TAG, "Could not detect Verified Boot state", e); Log.e(XposedApp.TAG, "Could not detect Verified Boot state", e);
@ -241,7 +222,7 @@ public class StatusInstallerFragment extends Fragment {
case 28: case 28:
return "Pie"; return "Pie";
case 29: case 29:
return "Q"; return "Ten";
case 30: case 30:
return "R"; 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; ? "/data/user_de/0/" + BuildConfig.APPLICATION_ID + "/" : BASE_DIR_LEGACY;
public static final String ENABLED_MODULES_LIST_FILE = (Build.VERSION.SDK_INT >= 24 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"; ? "/data/user_de/0/" + BuildConfig.APPLICATION_ID + "/" : BASE_DIR_LEGACY) + "conf/enabled_modules.list";
public static int WRITE_EXTERNAL_PERMISSION = 69;
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
private static XposedApp mInstance = null; private static XposedApp instance = null;
private static Thread mUiThread; private static Thread uiThread;
private static Handler mMainHandler; private static Handler mainHandler;
private SharedPreferences mPref; private SharedPreferences pref;
private AppCompatActivity mCurrentActivity = null; private AppCompatActivity currentActivity = null;
private boolean mIsUiLoaded = false; private boolean isUiLoaded = false;
public static XposedApp getInstance() { public static XposedApp getInstance() {
return mInstance; return instance;
} }
public static InstallZipUtil.XposedProp getXposedProp() { 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) { public static void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) { if (Thread.currentThread() != uiThread) {
mMainHandler.post(action); mainHandler.post(action);
} else { } else {
action.run(); 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() { public static Integer getXposedVersion() {
return getActiveXposedVersion(); return getActiveXposedVersion();
} }
public static SharedPreferences getPreferences() { public static SharedPreferences getPreferences() {
return mInstance.mPref; return instance.pref;
}
public static String getDownloadPath() {
return getPreferences().getString("download_location", Environment.getExternalStorageDirectory() + "/Download/EdXposedManager/");
} }
public static void mkdirAndChmod(String dir, int permissions) { 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; instance = this;
mUiThread = Thread.currentThread(); uiThread = Thread.currentThread();
mMainHandler = new Handler(); mainHandler = new Handler();
mPref = PreferenceManager.getDefaultSharedPreferences(this); pref = PreferenceManager.getDefaultSharedPreferences(this);
de.robv.android.xposed.installer.XposedApp.getInstance().reloadXposedProp(); de.robv.android.xposed.installer.XposedApp.getInstance().reloadXposedProp();
createDirectories(); 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"); @SuppressLint("SimpleDateFormat") DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = new Date(); Date date = new Date();
if (!Objects.requireNonNull(mPref.getString("date", "")).equals(dateFormat.format(date))) { if (!Objects.requireNonNull(pref.getString("date", "")).equals(dateFormat.format(date))) {
mPref.edit().putString("date", dateFormat.format(date)).apply(); pref.edit().putString("date", dateFormat.format(date)).apply();
try { try {
Log.i(TAG, String.format("EdXposedManager - %s - %s", BuildConfig.VERSION_CODE, getPackageManager().getPackageInfo(getPackageName(), 0).versionName)); 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(); Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics(); DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration(); 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(); File[] files = file.listFiles();
if (files != null) for (File f : file.listFiles()) delete(f); if (files != null) for (File f : file.listFiles()) delete(f);
} }
//noinspection ResultOfMethodCallIgnored
file.delete(); file.delete();
} }
} }
@SuppressWarnings("JavaReflectionMemberAccess") @SuppressWarnings({"JavaReflectionMemberAccess", "OctalInteger"})
@SuppressLint({"PrivateApi", "NewApi"}) @SuppressLint({"PrivateApi", "NewApi"})
private void createDirectories() { private void createDirectories() {
FileUtils.setPermissions(BASE_DIR, 00777, -1, -1); 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(); final boolean isLoading = RepoLoader.getInstance().isLoading() || ModuleUtil.getInstance().isLoading();
runOnUiThread(() -> { runOnUiThread(() -> {
synchronized (XposedApp.this) { synchronized (XposedApp.this) {
if (mCurrentActivity != null) { if (currentActivity != null) {
if (refreshLayout != null) if (refreshLayout != null)
refreshLayout.setRefreshing(isLoading); refreshLayout.setRefreshing(isLoading);
} }
@ -226,12 +210,12 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
@Override @Override
public synchronized void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) { public synchronized void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
if (mIsUiLoaded) { if (isUiLoaded) {
return; return;
} }
RepoLoader.getInstance().triggerFirstLoadIfNecessary(); RepoLoader.getInstance().triggerFirstLoadIfNecessary();
mIsUiLoaded = true; isUiLoaded = true;
} }
@Override @Override
@ -241,13 +225,13 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
@Override @Override
public synchronized void onActivityResumed(@NonNull Activity activity) { public synchronized void onActivityResumed(@NonNull Activity activity) {
mCurrentActivity = (AppCompatActivity) activity; currentActivity = (AppCompatActivity) activity;
updateProgressIndicator(null); updateProgressIndicator(null);
} }
@Override @Override
public synchronized void onActivityPaused(Activity activity) { public synchronized void onActivityPaused(Activity activity) {
mCurrentActivity = null; currentActivity = null;
} }
@Override @Override

View File

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

View File

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

View File

@ -10,10 +10,15 @@ import org.meowcat.edxposed.manager.util.DownloadsUtil;
public class DownloadReceiver extends BroadcastReceiver { public class DownloadReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(final Context context, final Intent intent) { public void onReceive(final Context context, final Intent intent) {
try {
String action = intent.getAction(); String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
DownloadsUtil.triggerDownloadFinishedCallback(context, downloadId); 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; import java.util.Objects;
public class PackageChangeReceiver extends BroadcastReceiver { public class PackageChangeReceiver extends BroadcastReceiver {
private static ModuleUtil mModuleUtil = null; private static ModuleUtil moduleUtil = null;
private static String getPackageName(Intent intent) { private static String getPackageName(Intent intent) {
Uri uri = intent.getData(); Uri uri = intent.getData();
@ -49,22 +49,22 @@ public class PackageChangeReceiver extends BroadcastReceiver {
return; return;
} }
mModuleUtil = getModuleUtilInstance(); moduleUtil = getModuleUtilInstance();
InstalledModule module = ModuleUtil.getInstance().reloadSingleModule(packageName); InstalledModule module = ModuleUtil.getInstance().reloadSingleModule(packageName);
if (module == null if (module == null
|| intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { || intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
// Package being removed, disable it if it was a previously active // Package being removed, disable it if it was a previously active
// Xposed mod // Xposed mod
if (mModuleUtil.isModuleEnabled(packageName)) { if (moduleUtil.isModuleEnabled(packageName)) {
mModuleUtil.setModuleEnabled(packageName, false); moduleUtil.setModuleEnabled(packageName, false);
mModuleUtil.updateModulesList(false); moduleUtil.updateModulesList(false);
} }
return; return;
} }
if (mModuleUtil.isModuleEnabled(packageName)) { if (moduleUtil.isModuleEnabled(packageName)) {
mModuleUtil.updateModulesList(false); moduleUtil.updateModulesList(false);
NotificationUtil.showModulesUpdatedNotification(); NotificationUtil.showModulesUpdatedNotification();
} else { } else {
NotificationUtil.showNotActivatedNotification(packageName, module.getAppName()); NotificationUtil.showNotActivatedNotification(packageName, module.getAppName());
@ -72,9 +72,9 @@ public class PackageChangeReceiver extends BroadcastReceiver {
} }
private ModuleUtil getModuleUtilInstance() { private ModuleUtil getModuleUtilInstance() {
if (mModuleUtil == null) { if (moduleUtil == null) {
mModuleUtil = ModuleUtil.getInstance(); moduleUtil = ModuleUtil.getInstance();
} }
return mModuleUtil; return moduleUtil;
} }
} }

View File

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

View File

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

View File

@ -29,60 +29,6 @@ public class JSONUtils {
return sb.toString(); 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 class XposedJson {
public List<XposedTab> tabs; public List<XposedTab> tabs;
public ApkRelease apk; public ApkRelease apk;

View File

@ -48,31 +48,6 @@ public class XposedTab implements Parcelable {
official = in.readByte() != 0; 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 @Override
public int describeContents() { public int describeContents() {
return 0; return 0;

View File

@ -26,7 +26,7 @@ public class XposedZip {
List<XposedZip> list; List<XposedZip> list;
public MyAdapter(Context context, List<XposedZip> objects) { 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.context = context;
this.list = objects; this.list = objects;
} }
@ -57,7 +57,7 @@ public class XposedZip {
return row; return row;
} }
private class ItemHolder { private static class ItemHolder {
TextView name; TextView name;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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