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