Remove storage permission
This commit is contained in:
parent
d2914f947d
commit
ed8836ca6d
|
|
@ -4,8 +4,6 @@
|
|||
package="org.meowcat.edxposed.manager">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
|
@ -98,7 +96,7 @@
|
|||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="org.meowcat.edxposed.manager.fileprovider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public class XposedApp extends Application {
|
|||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mInstance = this;
|
||||
reloadXposedProp();
|
||||
}
|
||||
|
||||
public void reloadXposedProp() {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
|
|
@ -20,7 +17,6 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.StyleRes;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
|
|
@ -152,16 +148,6 @@ public class BaseActivity extends AppCompatActivity {
|
|||
.show();
|
||||
}
|
||||
|
||||
public boolean checkPermissions() {
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, XposedApp.WRITE_EXTERNAL_PERMISSION);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void reboot(String mode) {
|
||||
if (!Shell.rootAccess()) {
|
||||
showAlert(getString(R.string.root_failed));
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
@ -20,11 +16,9 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.meowcat.edxposed.manager.util.NavUtil;
|
||||
import org.meowcat.edxposed.manager.util.json.XposedTab;
|
||||
|
|
@ -33,8 +27,6 @@ import org.meowcat.edxposed.manager.util.json.XposedZip;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.meowcat.edxposed.manager.XposedApp.WRITE_EXTERNAL_PERMISSION;
|
||||
|
||||
public class BaseAdvancedInstaller extends Fragment {
|
||||
private View mClickedButton;
|
||||
|
||||
|
|
@ -88,16 +80,6 @@ public class BaseAdvancedInstaller extends Fragment {
|
|||
return Objects.requireNonNull(tab).description;
|
||||
}
|
||||
|
||||
private boolean checkPermissions() {
|
||||
if (Build.VERSION.SDK_INT < 23) return false;
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(Objects.requireNonNull(getActivity()), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
|
@ -143,31 +125,21 @@ public class BaseAdvancedInstaller extends Fragment {
|
|||
.setMessage(s).setPositiveButton(android.R.string.ok, null).show();
|
||||
});
|
||||
|
||||
btnInstall.setOnClickListener(v -> {
|
||||
mClickedButton = v;
|
||||
if (checkPermissions()) return;
|
||||
btnInstall.setOnClickListener(v -> areYouSure(R.string.warningArchitecture,
|
||||
(dialog, which) -> {
|
||||
XposedZip selectedInstaller = (XposedZip) chooserInstallers.getSelectedItem();
|
||||
Uri uri = Uri.parse(selectedInstaller.link);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
}));
|
||||
|
||||
areYouSure(R.string.warningArchitecture,
|
||||
(dialog, which) -> {
|
||||
XposedZip selectedInstaller = (XposedZip) chooserInstallers.getSelectedItem();
|
||||
Uri uri = Uri.parse(selectedInstaller.link);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
});
|
||||
});
|
||||
|
||||
btnUninstall.setOnClickListener(v -> {
|
||||
mClickedButton = v;
|
||||
if (checkPermissions()) return;
|
||||
|
||||
areYouSure(R.string.warningArchitecture,
|
||||
(dialog, which) -> {
|
||||
XposedZip selectedUninstaller = (XposedZip) chooserUninstallers.getSelectedItem();
|
||||
Uri uri = Uri.parse(selectedUninstaller.link);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
});
|
||||
});
|
||||
btnUninstall.setOnClickListener(v -> areYouSure(R.string.warningArchitecture,
|
||||
(dialog, which) -> {
|
||||
XposedZip selectedUninstaller = (XposedZip) chooserUninstallers.getSelectedItem();
|
||||
Uri uri = Uri.parse(selectedUninstaller.link);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
}));
|
||||
|
||||
noticeTv.setText(Html.fromHtml(notice()));
|
||||
author.setText(getString(R.string.download_author, author()));
|
||||
|
|
@ -198,20 +170,6 @@ public class BaseAdvancedInstaller extends Fragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == WRITE_EXTERNAL_PERMISSION) {
|
||||
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (mClickedButton != null) {
|
||||
new Handler().postDelayed(() -> mClickedButton.performClick(), 500);
|
||||
}
|
||||
} else {
|
||||
Snackbar.make(getActivity().findViewById(R.id.snackbar), R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private void areYouSure(int contentTextId, DialogInterface.OnClickListener listener) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
|
@ -73,7 +72,7 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba
|
|||
@Override
|
||||
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_app_list, menu);
|
||||
mSearchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search));
|
||||
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
mSearchView.setOnQueryTextListener(mSearchListener);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
|
@ -126,11 +125,6 @@ public class BlackListActivity extends BaseActivity implements AppAdapter.Callba
|
|||
AppHelper.showMenu(this, getSupportFragmentManager(), v, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPointerCaptureChanged(boolean hasCapture) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mSearchView.isIconified()) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
|
@ -68,15 +67,10 @@ public class CompatListActivity extends BaseActivity implements AppAdapter.Callb
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_app_list, menu);
|
||||
mSearchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search));
|
||||
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
mSearchView.setOnQueryTextListener(mSearchListener);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
|
@ -153,8 +152,7 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis
|
|||
getMenuInflater().inflate(R.menu.menu_download, menu);
|
||||
|
||||
// Setup search button
|
||||
final MenuItem searchItem = menu.findItem(R.id.menu_search);
|
||||
mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
|
||||
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
mSearchView.setIconifiedByDefault(true);
|
||||
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
|
|
@ -20,6 +21,7 @@ import org.meowcat.edxposed.manager.util.chrome.LinkTransformationMethod;
|
|||
|
||||
public class DownloadDetailsFragment extends Fragment {
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
DownloadDetailsActivity mActivity = (DownloadDetailsActivity) getActivity();
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class DownloadDetailsSettingsFragment extends PreferenceFragmentCompat {
|
|||
|
||||
if (prefs.getBoolean("no_global", true)) {
|
||||
for (Map.Entry<String, ?> k : prefs.getAll().entrySet()) {
|
||||
if (prefs.getString(k.getKey(), "").equals("global")) {
|
||||
if (("global").equals(prefs.getString(k.getKey(), ""))) {
|
||||
editor.putString(k.getKey(), "").apply();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
@ -35,11 +39,11 @@ import org.meowcat.edxposed.manager.util.chrome.LinkTransformationMethod;
|
|||
import org.meowcat.edxposed.manager.widget.DownloadView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.meowcat.edxposed.manager.XposedApp.WRITE_EXTERNAL_PERMISSION;
|
||||
|
||||
public class DownloadDetailsVersionsFragment extends ListFragment {
|
||||
private static View rootView;
|
||||
private DownloadDetailsActivity mActivity;
|
||||
|
|
@ -93,13 +97,31 @@ public class DownloadDetailsVersionsFragment extends ListFragment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == WRITE_EXTERNAL_PERMISSION) {
|
||||
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
DownloadView.mClickedButton.performClick();
|
||||
} else {
|
||||
Snackbar.make(rootView, R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
if (requestCode == 42) {
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
try {
|
||||
OutputStream os = mActivity.getContentResolver().openOutputStream(uri);
|
||||
if (os != null) {
|
||||
FileInputStream in = new FileInputStream(new File(DownloadView.mInfo.localFilename));
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
//Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,10 +83,6 @@ public class EdDownloadActivity extends BaseActivity {
|
|||
@SuppressLint("StaticFieldLeak")
|
||||
private class JSONParser extends AsyncTask<Void, Void, String> {
|
||||
|
||||
private String newApkVersion = null;
|
||||
private String newApkLink = null;
|
||||
private String newApkChangelog = null;
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
try {
|
||||
|
|
@ -115,9 +111,9 @@ public class EdDownloadActivity extends BaseActivity {
|
|||
tabsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
newApkVersion = xposedJson.apk.version;
|
||||
newApkLink = xposedJson.apk.link;
|
||||
newApkChangelog = xposedJson.apk.changelog;
|
||||
String newApkVersion = xposedJson.apk.version;
|
||||
String newApkLink = xposedJson.apk.link;
|
||||
String newApkChangelog = xposedJson.apk.changelog;
|
||||
|
||||
if (newApkVersion == null) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
|
@ -23,7 +19,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
|
@ -36,6 +31,7 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
|
|
@ -48,7 +44,6 @@ public class LogsActivity extends BaseActivity {
|
|||
XposedApp.BASE_DIR + "log/error.log.old");
|
||||
private File mFileAllLog = new File(XposedApp.BASE_DIR + "log/all.log");
|
||||
private File mFileAllLogOld = new File(XposedApp.BASE_DIR + "log/all.log.old");
|
||||
private MenuItem mClickedMenuItem = null;
|
||||
private LogsAdapter mAdapter;
|
||||
private RecyclerView mListView;
|
||||
private Handler handler = new Handler();
|
||||
|
|
@ -124,7 +119,6 @@ public class LogsActivity extends BaseActivity {
|
|||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
mClickedMenuItem = item;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_scroll_top:
|
||||
scrollTop();
|
||||
|
|
@ -138,7 +132,8 @@ public class LogsActivity extends BaseActivity {
|
|||
case R.id.menu_send:
|
||||
try {
|
||||
send();
|
||||
} catch (NullPointerException ignored) {
|
||||
} catch (Exception e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), e.getLocalizedMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
case R.id.menu_save:
|
||||
|
|
@ -186,34 +181,8 @@ public class LogsActivity extends BaseActivity {
|
|||
startActivity(Intent.createChooser(sendIntent, getResources().getString(R.string.menuSend)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode,
|
||||
@NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions,
|
||||
grantResults);
|
||||
if (requestCode == XposedApp.WRITE_EXTERNAL_PERMISSION) {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (mClickedMenuItem != null) {
|
||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||
}
|
||||
} else {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void save() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, XposedApp.WRITE_EXTERNAL_PERMISSION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Calendar now = Calendar.getInstance();
|
||||
String filename = String.format(
|
||||
"EdXposed_Verbose_%04d%02d%02d_%02d%02d%02d.log",
|
||||
|
|
@ -221,22 +190,39 @@ public class LogsActivity extends BaseActivity {
|
|||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||
|
||||
File targetFile = new File(XposedApp.createFolder(), filename);
|
||||
Intent exportIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
exportIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
exportIntent.setType("text/*");
|
||||
exportIntent.putExtra(Intent.EXTRA_TITLE, filename);
|
||||
startActivityForResult(exportIntent, 42);
|
||||
}
|
||||
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(allLog ? mFileAllLog : mFileErrorLog);
|
||||
FileOutputStream out = new FileOutputStream(targetFile);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode != RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
if (requestCode == 42) {
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
try {
|
||||
OutputStream os = getContentResolver().openOutputStream(uri);
|
||||
if (os != null) {
|
||||
FileInputStream in = new FileInputStream(allLog ? mFileAllLog : mFileErrorLog);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
Snackbar.make(findViewById(R.id.snackbar), targetFile.toString(), Snackbar.LENGTH_LONG).show();
|
||||
} catch (IOException e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.view.menu.MenuBuilder;
|
||||
import androidx.appcompat.view.menu.MenuPopupHelper;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
|
@ -70,9 +68,7 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
|
|||
PopupMenu appMenu = new PopupMenu(MainActivity.this, menu);
|
||||
appMenu.inflate(R.menu.menu_installer);
|
||||
appMenu.setOnMenuItemClickListener(this::onOptionsItemSelected);
|
||||
MenuPopupHelper menuHelper = new MenuPopupHelper(MainActivity.this, (MenuBuilder) appMenu.getMenu(), menu);
|
||||
menuHelper.setForceShowIcon(true);
|
||||
menuHelper.show();
|
||||
appMenu.show();
|
||||
});
|
||||
String installedXposedVersion;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
package org.meowcat.edxposed.manager;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -24,7 +20,6 @@ import androidx.annotation.NonNull;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
|
@ -43,15 +38,11 @@ import org.meowcat.edxposed.manager.util.NavUtil;
|
|||
import org.meowcat.edxposed.manager.util.RepoLoader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
|
@ -77,7 +68,6 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
private DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
private ModuleUtil mModuleUtil;
|
||||
private ModuleAdapter mAdapter = null;
|
||||
private MenuItem mClickedMenuItem = null;
|
||||
private RecyclerView mListView;
|
||||
private SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
private Runnable reloadModules = new Runnable() {
|
||||
|
|
@ -162,152 +152,140 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_modules, menu);
|
||||
mSearchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search));
|
||||
mSearchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
|
||||
mSearchView.setOnQueryTextListener(mSearchListener);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions,
|
||||
grantResults);
|
||||
if (requestCode == XposedApp.WRITE_EXTERNAL_PERMISSION) {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (mClickedMenuItem != null) {
|
||||
new Handler().postDelayed(() -> onOptionsItemSelected(mClickedMenuItem), 500);
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode != RESULT_OK) {
|
||||
return;
|
||||
}
|
||||
if (requestCode == 42) {
|
||||
File listModules = new File(XposedApp.ENABLED_MODULES_LIST_FILE);
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
try {
|
||||
OutputStream os = getContentResolver().openOutputStream(uri);
|
||||
if (os != null) {
|
||||
FileInputStream in = new FileInputStream(listModules);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
os.write(buffer, 0, len);
|
||||
}
|
||||
os.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (requestCode == 43) {
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
try {
|
||||
OutputStream os = getContentResolver().openOutputStream(uri);
|
||||
if (os != null) {
|
||||
PrintWriter fileOut = new PrintWriter(os);
|
||||
|
||||
Set<String> keys = ModuleUtil.getInstance().getModules().keySet();
|
||||
for (String key1 : keys) {
|
||||
fileOut.println(key1);
|
||||
}
|
||||
fileOut.close();
|
||||
os.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (requestCode == 44) {
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
try {
|
||||
importModules(uri);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.permissionNotGranted, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
File enabledModulesPath = new File(XposedApp.createFolder(), "enabled_modules.list");
|
||||
File installedModulesPath = new File(XposedApp.createFolder(), "installed_modules.list");
|
||||
File listModules = new File(XposedApp.ENABLED_MODULES_LIST_FILE);
|
||||
|
||||
mClickedMenuItem = item;
|
||||
|
||||
if (checkPermissions())
|
||||
return false;
|
||||
|
||||
Intent intent;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.export_enabled_modules:
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ModuleUtil.getInstance().getEnabledModules().isEmpty()) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.no_enabled_modules, Snackbar.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
XposedApp.createFolder();
|
||||
|
||||
FileInputStream in = new FileInputStream(listModules);
|
||||
FileOutputStream out = new FileOutputStream(enabledModulesPath);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
Snackbar.make(findViewById(R.id.snackbar), enabledModulesPath.toString(), Snackbar.LENGTH_LONG).show();
|
||||
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("text/*");
|
||||
intent.putExtra(Intent.EXTRA_TITLE, "enabled_modules.list");
|
||||
startActivityForResult(intent, 42);
|
||||
return true;
|
||||
case R.id.export_installed_modules:
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
Map<String, ModuleUtil.InstalledModule> installedModules = ModuleUtil.getInstance().getModules();
|
||||
|
||||
if (installedModules.isEmpty()) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.no_installed_modules, Snackbar.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
XposedApp.createFolder();
|
||||
|
||||
FileWriter fw = new FileWriter(installedModulesPath);
|
||||
BufferedWriter bw = new BufferedWriter(fw);
|
||||
PrintWriter fileOut = new PrintWriter(bw);
|
||||
|
||||
Set<String> keys = installedModules.keySet();
|
||||
for (String key1 : keys) {
|
||||
fileOut.println(key1);
|
||||
}
|
||||
|
||||
fileOut.close();
|
||||
} catch (IOException e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getResources().getString(R.string.logs_save_failed) + "\n" + e.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
Snackbar.make(findViewById(R.id.snackbar), installedModulesPath.toString(), Snackbar.LENGTH_LONG).show();
|
||||
intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("text/*");
|
||||
intent.putExtra(Intent.EXTRA_TITLE, "installed_modules.list");
|
||||
startActivityForResult(intent, 43);
|
||||
return true;
|
||||
case R.id.import_installed_modules:
|
||||
return importModules(installedModulesPath);
|
||||
case R.id.import_enabled_modules:
|
||||
return importModules(enabledModulesPath);
|
||||
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
startActivityForResult(intent, 44);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private boolean importModules(File path) {
|
||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.sdcard_not_writable, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
InputStream ips = null;
|
||||
private void importModules(Uri uri) {
|
||||
RepoLoader repoLoader = RepoLoader.getInstance();
|
||||
List<Module> list = new ArrayList<>();
|
||||
if (!path.exists()) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.no_backup_found, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ips = new FileInputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(XposedApp.TAG, "ModulesFragment -> " + e.getMessage());
|
||||
}
|
||||
|
||||
if (path.length() == 0) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), R.string.file_is_empty, Snackbar.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
assert ips != null;
|
||||
InputStreamReader ipsr = new InputStreamReader(ips);
|
||||
BufferedReader br = new BufferedReader(ipsr);
|
||||
InputStream inputStream = getContentResolver().openInputStream(uri);
|
||||
InputStreamReader isr = new InputStreamReader(inputStream);
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
Module m = repoLoader.getModule(line);
|
||||
|
||||
if (m == null) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), getString(R.string.download_details_not_found,
|
||||
line), Snackbar.LENGTH_SHORT).show();
|
||||
Snackbar.make(findViewById(R.id.snackbar), getString(R.string.download_details_not_found, line), Snackbar.LENGTH_SHORT).show();
|
||||
} else {
|
||||
list.add(m);
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
} catch (ActivityNotFoundException | IOException e) {
|
||||
Snackbar.make(findViewById(R.id.snackbar), e.toString(), Snackbar.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Snackbar.make(findViewById(R.id.snackbar), e.getLocalizedMessage(), Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
for (final Module m : list) {
|
||||
if (mModuleUtil.getModule(m.packageName) != null) {
|
||||
continue;
|
||||
}
|
||||
ModuleVersion mv = null;
|
||||
for (int i = 0; i < m.versions.size(); i++) {
|
||||
ModuleVersion mvTemp = m.versions.get(i);
|
||||
|
|
@ -319,13 +297,11 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
|||
}
|
||||
|
||||
if (mv != null) {
|
||||
DownloadsUtil.addModule(this, m.name, mv.downloadLink, false, (context, info) -> new InstallApkUtil(this, info).execute());
|
||||
DownloadsUtil.addModule(this, m.name, mv.downloadLink, (context, info) -> new InstallApkUtil(this, info).execute());
|
||||
}
|
||||
}
|
||||
|
||||
ModuleUtil.getInstance().reloadInstalledModules();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -3,13 +3,9 @@ package org.meowcat.edxposed.manager;
|
|||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileUtils;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -28,13 +24,10 @@ import java.io.File;
|
|||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public class StatusInstallerFragment extends Fragment {
|
||||
|
||||
public static final File DISABLE_FILE = new File(XposedApp.BASE_DIR + "conf/disabled");
|
||||
private static AppCompatActivity sActivity;
|
||||
private static String mUpdateLink;
|
||||
private static View mUpdateView;
|
||||
|
|
@ -98,20 +91,6 @@ public class StatusInstallerFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
@SuppressLint({"WorldReadableFiles", "WorldWriteableFiles"})
|
||||
private static void setFilePermissionsFromMode(String name, int mode) {
|
||||
int perms = FileUtils.S_IRUSR | FileUtils.S_IWUSR
|
||||
| FileUtils.S_IRGRP | FileUtils.S_IWGRP;
|
||||
if ((mode & Context.MODE_WORLD_READABLE) != 0) {
|
||||
perms |= FileUtils.S_IROTH;
|
||||
}
|
||||
if ((mode & Context.MODE_WORLD_WRITEABLE) != 0) {
|
||||
perms |= FileUtils.S_IWOTH;
|
||||
}
|
||||
FileUtils.setPermissions(name, perms, -1, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
@ -119,7 +98,6 @@ public class StatusInstallerFragment extends Fragment {
|
|||
}
|
||||
|
||||
@SuppressLint("WorldReadableFiles")
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.status_installer, container, false);
|
||||
|
|
@ -156,8 +134,6 @@ public class StatusInstallerFragment extends Fragment {
|
|||
cpu.setText(getCompleteArch());
|
||||
|
||||
determineVerifiedBootState(v);
|
||||
|
||||
refreshKnownIssue();
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
@ -191,57 +167,58 @@ public class StatusInstallerFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private boolean checkAppInstalled(Context context, String pkgName) {
|
||||
if (pkgName == null || pkgName.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
List<PackageInfo> info = packageManager.getInstalledPackages(0);
|
||||
if (info == null || info.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < info.size(); i++) {
|
||||
if (pkgName.equals(info.get(i).packageName)) {
|
||||
return true;
|
||||
/*
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private boolean checkAppInstalled(Context context, String pkgName) {
|
||||
if (pkgName == null || pkgName.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
private void refreshKnownIssue() {
|
||||
String issueName = null;
|
||||
String issueLink = null;
|
||||
final ApplicationInfo appInfo = Objects.requireNonNull(getActivity()).getApplicationInfo();
|
||||
final File baseDir = new File(XposedApp.BASE_DIR);
|
||||
final File baseDirCanonical = getCanonicalFile(baseDir);
|
||||
final File baseDirActual = new File(Build.VERSION.SDK_INT >= 24 ? appInfo.deviceProtectedDataDir : appInfo.dataDir);
|
||||
final File baseDirActualCanonical = getCanonicalFile(baseDirActual);
|
||||
|
||||
if (new File("/system/framework/core.jar.jex").exists()) {
|
||||
issueName = "Aliyun OS";
|
||||
issueLink = "https://forum.xda-developers.com/showpost.php?p=52289793&postcount=5";
|
||||
// } else if (Build.VERSION.SDK_INT < 24 && (new File("/data/miui/DexspyInstaller.jar").exists() || checkClassExists("miui.dexspy.DexspyInstaller"))) {
|
||||
// issueName = "MIUI/Dexspy";
|
||||
// issueLink = "https://forum.xda-developers.com/showpost.php?p=52291098&postcount=6";
|
||||
// } else if (Build.VERSION.SDK_INT < 24 && new File("/system/framework/twframework.jar").exists()) {
|
||||
// issueName = "Samsung TouchWiz ROM";
|
||||
// issueLink = "https://forum.xda-developers.com/showthread.php?t=3034811";
|
||||
} else if (!baseDirCanonical.equals(baseDirActualCanonical)) {
|
||||
Log.e(XposedApp.TAG, "Base directory: " + getPathWithCanonicalPath(baseDir, baseDirCanonical));
|
||||
Log.e(XposedApp.TAG, "Expected: " + getPathWithCanonicalPath(baseDirActual, baseDirActualCanonical));
|
||||
issueName = getString(R.string.known_issue_wrong_base_directory, getPathWithCanonicalPath(baseDirActual, baseDirActualCanonical));
|
||||
} else if (!baseDir.exists()) {
|
||||
issueName = getString(R.string.known_issue_missing_base_directory);
|
||||
issueLink = "https://github.com/rovo89/XposedInstaller/issues/393";
|
||||
} else if (checkAppInstalled(getContext(), "com.solohsu.android.edxp.manager")) {
|
||||
issueName = getString(R.string.edxp_installer_installed);
|
||||
issueLink = getString(R.string.about_support);
|
||||
final PackageManager packageManager = context.getPackageManager();
|
||||
List<PackageInfo> info = packageManager.getInstalledPackages(0);
|
||||
if (info == null || info.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < info.size(); i++) {
|
||||
if (pkgName.equals(info.get(i).packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
private void refreshKnownIssue() {
|
||||
String issueName = null;
|
||||
String issueLink = null;
|
||||
final ApplicationInfo appInfo = Objects.requireNonNull(getActivity()).getApplicationInfo();
|
||||
final File baseDir = new File(XposedApp.BASE_DIR);
|
||||
final File baseDirCanonical = getCanonicalFile(baseDir);
|
||||
final File baseDirActual = new File(Build.VERSION.SDK_INT >= 24 ? appInfo.deviceProtectedDataDir : appInfo.dataDir);
|
||||
final File baseDirActualCanonical = getCanonicalFile(baseDirActual);
|
||||
|
||||
if (new File("/system/framework/core.jar.jex").exists()) {
|
||||
issueName = "Aliyun OS";
|
||||
issueLink = "https://forum.xda-developers.com/showpost.php?p=52289793&postcount=5";
|
||||
// } else if (Build.VERSION.SDK_INT < 24 && (new File("/data/miui/DexspyInstaller.jar").exists() || checkClassExists("miui.dexspy.DexspyInstaller"))) {
|
||||
// issueName = "MIUI/Dexspy";
|
||||
// issueLink = "https://forum.xda-developers.com/showpost.php?p=52291098&postcount=6";
|
||||
// } else if (Build.VERSION.SDK_INT < 24 && new File("/system/framework/twframework.jar").exists()) {
|
||||
// issueName = "Samsung TouchWiz ROM";
|
||||
// issueLink = "https://forum.xda-developers.com/showthread.php?t=3034811";
|
||||
} else if (!baseDirCanonical.equals(baseDirActualCanonical)) {
|
||||
Log.e(XposedApp.TAG, "Base directory: " + getPathWithCanonicalPath(baseDir, baseDirCanonical));
|
||||
Log.e(XposedApp.TAG, "Expected: " + getPathWithCanonicalPath(baseDirActual, baseDirActualCanonical));
|
||||
issueName = getString(R.string.known_issue_wrong_base_directory, getPathWithCanonicalPath(baseDirActual, baseDirActualCanonical));
|
||||
} else if (!baseDir.exists()) {
|
||||
issueName = getString(R.string.known_issue_missing_base_directory);
|
||||
issueLink = "https://github.com/rovo89/XposedInstaller/issues/393";
|
||||
} else if (checkAppInstalled(getContext(), "com.solohsu.android.edxp.manager")) {
|
||||
issueName = getString(R.string.edxp_installer_installed);
|
||||
issueLink = getString(R.string.about_support);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
private String getAndroidVersion() {
|
||||
switch (Build.VERSION.SDK_INT) {
|
||||
// case 16:
|
||||
|
|
@ -296,23 +273,24 @@ public class StatusInstallerFragment extends Fragment {
|
|||
return manufacturer;
|
||||
}
|
||||
|
||||
private File getCanonicalFile(File file) {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
Log.e(XposedApp.TAG, "Failed to get canonical file for " + file.getAbsolutePath(), e);
|
||||
return file;
|
||||
/*
|
||||
private File getCanonicalFile(File file) {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
Log.e(XposedApp.TAG, "Failed to get canonical file for " + file.getAbsolutePath(), e);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getPathWithCanonicalPath(File file, File canonical) {
|
||||
if (file.equals(canonical)) {
|
||||
return file.getAbsolutePath();
|
||||
} else {
|
||||
return file.getAbsolutePath() + " \u2192 " + canonical.getAbsolutePath();
|
||||
private String getPathWithCanonicalPath(File file, File canonical) {
|
||||
if (file.equals(canonical)) {
|
||||
return file.getAbsolutePath();
|
||||
} else {
|
||||
return file.getAbsolutePath() + " \u2192 " + canonical.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
private int extractIntPart(String str) {
|
||||
int result = 0, length = str.length();
|
||||
for (int offset = 0; offset < length; offset++) {
|
||||
|
|
|
|||
|
|
@ -105,31 +105,35 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem
|
|||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
try {
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
try {
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
throwable.printStackTrace(pw);
|
||||
String stackTraceString = sw.toString();
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
throwable.printStackTrace(pw);
|
||||
String stackTraceString = sw.toString();
|
||||
|
||||
//Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.
|
||||
//The limit is 1MB on Android but some devices seem to have it lower.
|
||||
//See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
|
||||
//And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171
|
||||
if (stackTraceString.length() > 131071) {
|
||||
String disclaimer = " [stack trace too large]";
|
||||
stackTraceString = stackTraceString.substring(0, 131071 - disclaimer.length()) + disclaimer;
|
||||
}
|
||||
Intent intent = new Intent(XposedApp.this, CrashReportActivity.class);
|
||||
intent.putExtra(BuildConfig.APPLICATION_ID + ".EXTRA_STACK_TRACE", stackTraceString);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
XposedApp.this.startActivity(intent);
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(10);
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
//Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.
|
||||
//The limit is 1MB on Android but some devices seem to have it lower.
|
||||
//See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html
|
||||
//And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171
|
||||
if (stackTraceString.length() > 131071) {
|
||||
String disclaimer = " [stack trace too large]";
|
||||
stackTraceString = stackTraceString.substring(0, 131071 - disclaimer.length()) + disclaimer;
|
||||
}
|
||||
Intent intent = new Intent(XposedApp.this, CrashReportActivity.class);
|
||||
intent.putExtra(BuildConfig.APPLICATION_ID + ".EXTRA_STACK_TRACE", stackTraceString);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
XposedApp.this.startActivity(intent);
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
System.exit(10);
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
mInstance = this;
|
||||
mUiThread = Thread.currentThread();
|
||||
mMainHandler = new Handler();
|
||||
|
|
|
|||
|
|
@ -4,26 +4,17 @@ import android.annotation.SuppressLint;
|
|||
import android.app.DownloadManager;
|
||||
import android.app.DownloadManager.Query;
|
||||
import android.app.DownloadManager.Request;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.os.EnvironmentCompat;
|
||||
|
||||
import org.meowcat.edxposed.manager.R;
|
||||
import org.meowcat.edxposed.manager.XposedApp;
|
||||
import org.meowcat.edxposed.manager.repo.Module;
|
||||
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
||||
import org.meowcat.edxposed.manager.repo.ReleaseType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
|
@ -40,7 +31,7 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
|
||||
public class DownloadsUtil {
|
||||
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 Map<String, DownloadFinishedCallback> mCallbacks = new HashMap<>();
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
|
|
@ -48,152 +39,55 @@ public class DownloadsUtil {
|
|||
private static final SharedPreferences mPref = mApp
|
||||
.getSharedPreferences("download_cache", Context.MODE_PRIVATE);
|
||||
|
||||
private static String DOWNLOAD_MODULES = "modules";
|
||||
|
||||
private static DownloadInfo add(Builder b) {
|
||||
Context context = b.mContext;
|
||||
removeAllForUrl(context, b.mUrl);
|
||||
|
||||
if (!b.mDialog) {
|
||||
synchronized (mCallbacks) {
|
||||
mCallbacks.put(b.mUrl, b.mCallback);
|
||||
}
|
||||
}
|
||||
|
||||
String savePath = "Download/EdXposedManager";
|
||||
if (b.mModule) {
|
||||
savePath += "/modules";
|
||||
synchronized (mCallbacks) {
|
||||
mCallbacks.put(b.mUrl, b.mCallback);
|
||||
}
|
||||
|
||||
Request request = new Request(Uri.parse(b.mUrl));
|
||||
request.setTitle(b.mTitle);
|
||||
request.setMimeType(b.mMimeType.toString());
|
||||
if (b.mSave) {
|
||||
/*if (b.mSave) {
|
||||
try {
|
||||
request.setDestinationInExternalPublicDir(savePath, b.mTitle + b.mMimeType.getExtension());
|
||||
} catch (IllegalStateException e) {
|
||||
Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else if (b.mDestination != null) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
b.mDestination.getParentFile().mkdirs();
|
||||
removeAllForLocalFile(context, b.mDestination);
|
||||
request.setDestinationUri(Uri.fromFile(b.mDestination));
|
||||
}
|
||||
|
||||
} else */
|
||||
File destination = new File(context.getExternalCacheDir(), "/downloads/" + b.mTitle + b.mMimeType.getExtension());
|
||||
request.setDestinationUri(Uri.fromFile(destination));
|
||||
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE);
|
||||
|
||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
long id = dm.enqueue(request);
|
||||
|
||||
if (b.mDialog) {
|
||||
showDownloadDialog(b, id);
|
||||
}
|
||||
|
||||
return getById(context, id);
|
||||
}
|
||||
|
||||
private static File[] getDownloadDirs(String subDir) {
|
||||
Context context = XposedApp.getInstance();
|
||||
ArrayList<File> dirs = new ArrayList<>(2);
|
||||
for (File dir : ContextCompat.getExternalCacheDirs(context)) {
|
||||
if (dir != null && EnvironmentCompat.getStorageState(dir).equals(Environment.MEDIA_MOUNTED)) {
|
||||
dirs.add(new File(new File(dir, "downloads"), subDir));
|
||||
}
|
||||
}
|
||||
dirs.add(new File(new File(context.getCacheDir(), "downloads"), subDir));
|
||||
return dirs.toArray(new File[0]);
|
||||
}
|
||||
|
||||
private static File getDownloadTarget(String subDir, String filename) {
|
||||
return new File(getDownloadDirs(subDir)[0], filename);
|
||||
}
|
||||
|
||||
private static File getDownloadTargetForUrl(String subDir, String url) {
|
||||
return getDownloadTarget(subDir, Uri.parse(url).getLastPathSegment());
|
||||
}
|
||||
|
||||
public static DownloadInfo addModule(Context context, String title, String url, boolean save, DownloadFinishedCallback callback) {
|
||||
public static DownloadInfo addModule(Context context, String title, String url, DownloadFinishedCallback callback) {
|
||||
return new Builder(context)
|
||||
.setTitle(title)
|
||||
.setUrl(url)
|
||||
.setDestinationFromUrl(DownloadsUtil.DOWNLOAD_MODULES)
|
||||
.setCallback(callback)
|
||||
.setSave(save)
|
||||
.setModule(true)
|
||||
.setMimeType(MIME_TYPES.APK)
|
||||
.download();
|
||||
}
|
||||
|
||||
private static void showDownloadDialog(final Builder b, final long id) {
|
||||
final Context context = b.mContext;
|
||||
final ProgressDialog dialog = new ProgressDialog(context);
|
||||
dialog.setTitle(b.mTitle);
|
||||
dialog.setMessage(context.getString(R.string.download_view_waiting));
|
||||
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.download_view_cancel), (dialog1, which) -> dialog1.cancel());
|
||||
dialog.setOnCancelListener(dialog12 -> removeById(context, id));
|
||||
/*
|
||||
public static ModuleVersion getStableVersion(Module m) {
|
||||
for (int i = 0; i < m.versions.size(); i++) {
|
||||
ModuleVersion mvTemp = m.versions.get(i);
|
||||
|
||||
dialog.setProgress(0);
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.setProgressNumberFormat(context.getString(R.string.download_progress));
|
||||
dialog.show();
|
||||
|
||||
new Thread("DownloadDialog") {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
final DownloadInfo info = getById(context, id);
|
||||
if (info == null) {
|
||||
dialog.cancel();
|
||||
return;
|
||||
} else if (info.status == DownloadManager.STATUS_FAILED) {
|
||||
dialog.cancel();
|
||||
XposedApp.runOnUiThread(() -> Toast.makeText(context,
|
||||
context.getString(R.string.download_view_failed, info.reason),
|
||||
Toast.LENGTH_LONG).show());
|
||||
return;
|
||||
} else if (info.status == DownloadManager.STATUS_SUCCESSFUL) {
|
||||
dialog.dismiss();
|
||||
// Hack to reset stat information.
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
new File(info.localFilename).setExecutable(false);
|
||||
if (b.mCallback != null) {
|
||||
b.mCallback.onDownloadFinished(context, info);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
XposedApp.runOnUiThread(() -> {
|
||||
if (info.totalSize <= 0 || info.status != DownloadManager.STATUS_RUNNING) {
|
||||
dialog.setMessage(context.getString(R.string.download_view_waiting));
|
||||
} else {
|
||||
dialog.setMessage(context.getString(R.string.download_running));
|
||||
dialog.setProgress(info.bytesDownloaded / 1024);
|
||||
dialog.setMax(info.totalSize / 1024);
|
||||
}
|
||||
});
|
||||
if (mvTemp.relType == ReleaseType.STABLE) {
|
||||
return mvTemp;
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public static ModuleVersion getStableVersion(Module m) {
|
||||
for (int i = 0; i < m.versions.size(); i++) {
|
||||
ModuleVersion mvTemp = m.versions.get(i);
|
||||
|
||||
if (mvTemp.relType == ReleaseType.STABLE) {
|
||||
return mvTemp;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
*/
|
||||
public static DownloadInfo getById(Context context, long id) {
|
||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
Cursor c = dm.query(new Query().setFilterById(id));
|
||||
|
|
@ -317,7 +211,7 @@ public class DownloadsUtil {
|
|||
|
||||
dm.remove(ids);
|
||||
}
|
||||
|
||||
/*
|
||||
private static void removeAllForLocalFile(Context context, File file) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
|
|
@ -367,7 +261,7 @@ public class DownloadsUtil {
|
|||
ids[i] = idsList.get(i);
|
||||
|
||||
dm.remove(ids);
|
||||
}
|
||||
}*/
|
||||
|
||||
// public static void removeOutdated(Context context, long cutoff) {
|
||||
// DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
|
|
@ -563,9 +457,6 @@ public class DownloadsUtil {
|
|||
private String mUrl = null;
|
||||
private DownloadFinishedCallback mCallback = null;
|
||||
private MIME_TYPES mMimeType = MIME_TYPES.APK;
|
||||
private File mDestination = null;
|
||||
private boolean mDialog = false;
|
||||
private boolean mSave = false;
|
||||
|
||||
public Builder(Context context) {
|
||||
mContext = context;
|
||||
|
|
@ -591,33 +482,11 @@ public class DownloadsUtil {
|
|||
return this;
|
||||
}
|
||||
|
||||
Builder setDestination(File file) {
|
||||
mDestination = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder setDestinationFromUrl(String subDir) {
|
||||
if (mUrl == null) {
|
||||
throw new IllegalStateException("URL must be set first");
|
||||
}
|
||||
return setDestination(getDownloadTargetForUrl(subDir, mUrl));
|
||||
}
|
||||
|
||||
public Builder setSave(boolean save) {
|
||||
this.mSave = save;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setModule(boolean module) {
|
||||
this.mModule = module;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDialog(boolean dialog) {
|
||||
mDialog = dialog;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownloadInfo download() {
|
||||
return add(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package org.meowcat.edxposed.manager.widget;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.Intent;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
@ -12,9 +10,7 @@ import android.widget.Button;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.meowcat.edxposed.manager.R;
|
||||
|
|
@ -23,20 +19,15 @@ import org.meowcat.edxposed.manager.util.DownloadsUtil.DownloadFinishedCallback;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.meowcat.edxposed.manager.XposedApp.WRITE_EXTERNAL_PERMISSION;
|
||||
|
||||
public class DownloadView extends LinearLayout {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public static Button mClickedButton;
|
||||
public static DownloadsUtil.DownloadInfo mInfo = null;
|
||||
private final Button btnDownload;
|
||||
private final Button btnDownloadCancel;
|
||||
private final Button btnInstall;
|
||||
private final Button btnRemove;
|
||||
private final Button btnSave;
|
||||
private final ProgressBar progressBar;
|
||||
private final TextView txtInfo;
|
||||
public Fragment fragment;
|
||||
private DownloadsUtil.DownloadInfo mInfo = null;
|
||||
private String mUrl = null;
|
||||
private final Runnable refreshViewRunnable = new Runnable() {
|
||||
@Override
|
||||
|
|
@ -45,7 +36,6 @@ public class DownloadView extends LinearLayout {
|
|||
btnDownload.setVisibility(View.GONE);
|
||||
btnSave.setVisibility(View.GONE);
|
||||
btnDownloadCancel.setVisibility(View.GONE);
|
||||
btnRemove.setVisibility(View.GONE);
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
txtInfo.setVisibility(View.VISIBLE);
|
||||
|
|
@ -54,7 +44,6 @@ public class DownloadView extends LinearLayout {
|
|||
btnDownload.setVisibility(View.VISIBLE);
|
||||
btnSave.setVisibility(View.VISIBLE);
|
||||
btnDownloadCancel.setVisibility(View.GONE);
|
||||
btnRemove.setVisibility(View.GONE);
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
txtInfo.setVisibility(View.GONE);
|
||||
|
|
@ -66,7 +55,6 @@ public class DownloadView extends LinearLayout {
|
|||
btnDownload.setVisibility(View.GONE);
|
||||
btnSave.setVisibility(View.GONE);
|
||||
btnDownloadCancel.setVisibility(View.VISIBLE);
|
||||
btnRemove.setVisibility(View.GONE);
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
txtInfo.setVisibility(View.VISIBLE);
|
||||
|
|
@ -88,7 +76,6 @@ public class DownloadView extends LinearLayout {
|
|||
btnDownload.setVisibility(View.VISIBLE);
|
||||
btnSave.setVisibility(View.VISIBLE);
|
||||
btnDownloadCancel.setVisibility(View.GONE);
|
||||
btnRemove.setVisibility(View.GONE);
|
||||
btnInstall.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
txtInfo.setVisibility(View.VISIBLE);
|
||||
|
|
@ -98,9 +85,8 @@ public class DownloadView extends LinearLayout {
|
|||
|
||||
case DownloadManager.STATUS_SUCCESSFUL:
|
||||
btnDownload.setVisibility(View.GONE);
|
||||
btnSave.setVisibility(View.GONE);
|
||||
btnSave.setVisibility(View.VISIBLE);
|
||||
btnDownloadCancel.setVisibility(View.GONE);
|
||||
btnRemove.setVisibility(View.VISIBLE);
|
||||
btnInstall.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
txtInfo.setVisibility(View.VISIBLE);
|
||||
|
|
@ -123,27 +109,27 @@ public class DownloadView extends LinearLayout {
|
|||
|
||||
btnDownload = findViewById(R.id.btnDownload);
|
||||
btnDownloadCancel = findViewById(R.id.btnDownloadCancel);
|
||||
btnRemove = findViewById(R.id.btnRemove);
|
||||
btnInstall = findViewById(R.id.btnInstall);
|
||||
btnSave = findViewById(R.id.save);
|
||||
|
||||
btnDownload.setOnClickListener(v -> {
|
||||
mClickedButton = btnDownload;
|
||||
|
||||
mInfo = DownloadsUtil.addModule(getContext(), mTitle, mUrl, false, mCallback);
|
||||
mInfo = DownloadsUtil.addModule(getContext(), mTitle, mUrl, mCallback);
|
||||
refreshViewFromUiThread();
|
||||
|
||||
if (mInfo != null)
|
||||
new DownloadMonitor().start();
|
||||
});
|
||||
|
||||
btnSave.setOnClickListener(v -> {
|
||||
mClickedButton = btnSave;
|
||||
|
||||
if (checkPermissions())
|
||||
return;
|
||||
|
||||
mInfo = DownloadsUtil.addModule(getContext(), mTitle, mUrl, true, (context1, info) -> Toast.makeText(context1, context1.getString(R.string.module_saved, info.localFilename), Toast.LENGTH_SHORT).show());
|
||||
mInfo = DownloadsUtil.addModule(getContext(), mTitle, mUrl, (context1, info) -> {
|
||||
Intent exportIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
exportIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
exportIntent.setType(DownloadsUtil.MIME_TYPE_APK);
|
||||
exportIntent.putExtra(Intent.EXTRA_TITLE, mTitle + ".apk");
|
||||
fragment.startActivityForResult(exportIntent, 42);
|
||||
});
|
||||
refreshViewFromUiThread();
|
||||
if (mInfo != null)
|
||||
new DownloadMonitor().start();
|
||||
});
|
||||
|
||||
btnDownloadCancel.setOnClickListener(v -> {
|
||||
|
|
@ -154,14 +140,6 @@ public class DownloadView extends LinearLayout {
|
|||
// UI update will happen automatically by the DownloadMonitor
|
||||
});
|
||||
|
||||
btnRemove.setOnClickListener(v -> {
|
||||
if (mInfo == null)
|
||||
return;
|
||||
|
||||
DownloadsUtil.removeById(getContext(), mInfo.id);
|
||||
// UI update will happen automatically by the DownloadMonitor
|
||||
});
|
||||
|
||||
btnInstall.setOnClickListener(v -> {
|
||||
if (mCallback == null)
|
||||
return;
|
||||
|
|
@ -175,15 +153,6 @@ public class DownloadView extends LinearLayout {
|
|||
refreshViewFromUiThread();
|
||||
}
|
||||
|
||||
private boolean checkPermissions() {
|
||||
if (ActivityCompat.checkSelfPermission(this.getContext(),
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
fragment.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_PERMISSION);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void refreshViewFromUiThread() {
|
||||
refreshViewRunnable.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,16 +42,6 @@
|
|||
android:visibility="gone"
|
||||
tools:ignore="ButtonOrder" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnRemove"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="@string/download_view_remove"
|
||||
android:theme="@style/Widget.AppCompat.Button.Colored"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnInstall"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@
|
|||
|
||||
<!-- Logs tab -->
|
||||
<string name="logs_save_failed">无法将日志写入 SD 卡: </string>
|
||||
<string name="sdcard_not_writable">无法找到 SD 卡或不可写入</string>
|
||||
<string name="menuClearLog">立即清理日志</string>
|
||||
<string name="logs_cleared">日志清理成功</string>
|
||||
<string name="logs_clear_failed">无法清理日志: </string>
|
||||
|
|
@ -156,7 +155,6 @@
|
|||
<string name="download_could_not_read_file">无法读取下载的文件: %s</string>
|
||||
<string name="download_no_valid_apk">下载的文件并非有效的 APK (或存在兼容性问题)</string>
|
||||
<string name="download_incorrect_package_name">文件包名不正确(下载: %1$s, 预期: %2$s)</string>
|
||||
<string name="download_running">正在下载</string>
|
||||
|
||||
<!-- RepoLoader -->
|
||||
<string name="repo_download_failed_http">下载 %1$s 失败: %2$d(%3$s)</string>
|
||||
|
|
@ -173,7 +171,6 @@
|
|||
<string name="no_installed_modules">没有任何已安装的模块</string>
|
||||
<string name="enable_heads_up">启用浮动通知</string>
|
||||
<string name="enable_heads_up_summary">对新安装或已更新的模块启用浮动通知</string>
|
||||
<string name="no_backup_found">找不到备份</string>
|
||||
<string name="no_enabled_modules">没有任何已启用的模块</string>
|
||||
|
||||
<string name="share">分享</string>
|
||||
|
|
@ -195,7 +192,6 @@
|
|||
|
||||
<string name="changelog">更新日志</string>
|
||||
<string name="scroll_top">滚动到顶部</string>
|
||||
<string name="file_is_empty">文件为空</string>
|
||||
<string name="install_with_su">静默安装(root)</string>
|
||||
<string name="install_with_su_summ">勾选后在 EdXposed Manager 内安装模块时将不再显示安装提示</string>
|
||||
<string name="module_saved">模块已保存至 %1$s</string>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@
|
|||
|
||||
<!-- Logs tab -->
|
||||
<string name="logs_save_failed">無法將日誌寫入 SD 卡: </string>
|
||||
<string name="sdcard_not_writable">無法找到 SD 卡或不可寫入</string>
|
||||
<string name="menuClearLog">立即清理日誌</string>
|
||||
<string name="logs_cleared">日誌清理成功</string>
|
||||
<string name="logs_clear_failed">無法清理日誌: </string>
|
||||
|
|
@ -156,7 +155,6 @@
|
|||
<string name="download_could_not_read_file">無法讀取下載的文件: %s</string>
|
||||
<string name="download_no_valid_apk">下載的文件並非有效的 APK (或存在兼容性問題)</string>
|
||||
<string name="download_incorrect_package_name">文件包名不正確(下載: %1$s, 預期: %2$s)</string>
|
||||
<string name="download_running">正在下載</string>
|
||||
|
||||
<!-- RepoLoader -->
|
||||
<string name="repo_download_failed_http">下載 %1$s 失敗: %2$d(%3$s)</string>
|
||||
|
|
@ -173,7 +171,6 @@
|
|||
<string name="no_installed_modules">沒有任何已安裝的模塊</string>
|
||||
<string name="enable_heads_up">啟用浮動通知</string>
|
||||
<string name="enable_heads_up_summary">對新安裝或已更新的模塊啟用浮動通知</string>
|
||||
<string name="no_backup_found">找不到備份</string>
|
||||
<string name="no_enabled_modules">沒有任何已啟用的模塊</string>
|
||||
|
||||
<string name="share">分享</string>
|
||||
|
|
@ -195,7 +192,6 @@
|
|||
|
||||
<string name="changelog">更新日誌</string>
|
||||
<string name="scroll_top">滾動到頂部</string>
|
||||
<string name="file_is_empty">文件為空</string>
|
||||
<string name="install_with_su">靜默安裝(root)</string>
|
||||
<string name="install_with_su_summ">勾選後在 EdXposed Manager 內安裝模塊時將不再顯示安裝提示</string>
|
||||
<string name="module_saved">模塊已保存至 %1$s</string>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@
|
|||
|
||||
<!-- Logs tab -->
|
||||
<string name="logs_save_failed">無法將日誌寫入 SD 卡: </string>
|
||||
<string name="sdcard_not_writable">無法找到 SD 卡或不可寫入</string>
|
||||
<string name="menuClearLog">立即清理日誌</string>
|
||||
<string name="logs_cleared">日誌清理成功</string>
|
||||
<string name="logs_clear_failed">無法清理日誌: </string>
|
||||
|
|
@ -156,7 +155,6 @@
|
|||
<string name="download_could_not_read_file">無法讀取下載的檔案: %s</string>
|
||||
<string name="download_no_valid_apk">下載的檔案並非有效的 APK (或存在相容性問題)</string>
|
||||
<string name="download_incorrect_package_name">檔案包名不正確(下載: %1$s, 預期: %2$s)</string>
|
||||
<string name="download_running">正在下載</string>
|
||||
|
||||
<!-- RepoLoader -->
|
||||
<string name="repo_download_failed_http">下載 %1$s 失敗: %2$d(%3$s)</string>
|
||||
|
|
@ -173,7 +171,6 @@
|
|||
<string name="no_installed_modules">沒有任何已安裝的模組</string>
|
||||
<string name="enable_heads_up">啟用浮動通知</string>
|
||||
<string name="enable_heads_up_summary">對新安裝或已更新的模組啟用浮動通知</string>
|
||||
<string name="no_backup_found">找不到備份</string>
|
||||
<string name="no_enabled_modules">沒有任何已啟用的模組</string>
|
||||
|
||||
<string name="share">分享</string>
|
||||
|
|
@ -195,7 +192,6 @@
|
|||
|
||||
<string name="changelog">更新日誌</string>
|
||||
<string name="scroll_top">滾動到頂部</string>
|
||||
<string name="file_is_empty">檔案為空</string>
|
||||
<string name="install_with_su">靜默安裝(root)</string>
|
||||
<string name="install_with_su_summ">勾選後在 EdXposed Manager 內安裝模組時將不再顯示安裝提示</string>
|
||||
<string name="module_saved">模組已儲存至 %1$s</string>
|
||||
|
|
|
|||
|
|
@ -128,7 +128,6 @@
|
|||
|
||||
<!-- Logs tab -->
|
||||
<string name="logs_save_failed">Could not write log to SD card:</string>
|
||||
<string name="sdcard_not_writable">SD card not found or not writable</string>
|
||||
<string name="menuClearLog">Clear log now</string>
|
||||
<string name="logs_cleared">Log successfully cleared.</string>
|
||||
<string name="logs_clear_failed">Could not clear the log:</string>
|
||||
|
|
@ -158,8 +157,6 @@
|
|||
<string name="download_could_not_read_file">Could not read downloaded file: %s</string>
|
||||
<string name="download_no_valid_apk">Downloaded file is not a valid APK (or incompatible)</string>
|
||||
<string name="download_incorrect_package_name">Package name is incorrect (downloaded: %1$s, expected: %2$s)</string>
|
||||
<string name="download_running">Download is running</string>
|
||||
<string name="download_progress" translatable="false">%1$,d / %2$,d kB</string>
|
||||
|
||||
<!-- RepoLoader -->
|
||||
<string name="repo_download_failed_http">Downloading %1$s failed: %2$d (%3$s)</string>
|
||||
|
|
@ -176,7 +173,6 @@
|
|||
<string name="no_installed_modules">There are no installed modules!</string>
|
||||
<string name="enable_heads_up">Enable Heads-Up notification</string>
|
||||
<string name="enable_heads_up_summary">This option enables heads up notification on new/updated module</string>
|
||||
<string name="no_backup_found">No backup found</string>
|
||||
<string name="no_enabled_modules">There are no modules enabled</string>
|
||||
|
||||
<string name="share">Share with…</string>
|
||||
|
|
@ -198,7 +194,6 @@
|
|||
|
||||
<string name="changelog">Changelog</string>
|
||||
<string name="scroll_top">Scroll to top</string>
|
||||
<string name="file_is_empty">File is empty</string>
|
||||
<string name="install_with_su">Silent installation (root)</string>
|
||||
<string name="install_with_su_summ">If checked EdXposed Manager will install modules without a prompt</string>
|
||||
<string name="module_saved">Module saved at %1$s</string>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
<paths>
|
||||
<external-cache-path
|
||||
name="downloads"
|
||||
path="downloads" />
|
||||
<external-path
|
||||
name="download"
|
||||
path="Download" />
|
||||
path="/downloads" />
|
||||
<!--suppress AndroidElementNotAllowed -->
|
||||
<root-path
|
||||
name="log_legacy"
|
||||
|
|
|
|||
Loading…
Reference in New Issue