From fac904009db2df6f77864ab22d6bec71f33e67ec Mon Sep 17 00:00:00 2001 From: NekoInverter <42698724+NekoInverter@users.noreply.github.com> Date: Thu, 6 Feb 2020 17:24:23 +0800 Subject: [PATCH] Fix possible crash & add crash report activity --- app/src/main/AndroidManifest.xml | 3 + .../edxposed/manager/BaseActivity.java | 31 +-- .../edxposed/manager/CrashReportActivity.java | 120 ++++++++++ .../edxposed/manager/DownloadActivity.java | 11 +- .../DownloadDetailsVersionsFragment.java | 3 +- .../edxposed/manager/ModulesActivity.java | 215 +++++++----------- .../meowcat/edxposed/manager/XposedApp.java | 27 +++ .../main/res/layout/activity_crash_report.xml | 70 ++++++ app/src/main/res/layout/activity_download.xml | 5 +- app/src/main/res/menu/menu_app_list.xml | 44 ++++ app/src/main/res/menu/menu_installer.xml | 73 +++--- app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 15 files changed, 417 insertions(+), 189 deletions(-) create mode 100644 app/src/main/java/org/meowcat/edxposed/manager/CrashReportActivity.java create mode 100644 app/src/main/res/layout/activity_crash_report.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8a76842c..512c456b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,6 +21,9 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning"> + diff --git a/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java index 26f45f6f..76e15382 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/BaseActivity.java @@ -13,13 +13,11 @@ import android.os.Looper; import android.text.TextUtils; import android.view.MenuItem; import android.view.View; -import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StyleRes; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; import androidx.core.app.ActivityCompat; @@ -119,8 +117,10 @@ public class BaseActivity extends AppCompatActivity { } void softReboot() { - if (startShell()) + if (!Shell.rootAccess()) { + showAlert(getString(R.string.root_failed)); return; + } List messages = new LinkedList<>(); Shell.Result result = Shell.su("setprop ctl.restart surfaceflinger; setprop ctl.restart zygote").exec(); @@ -132,29 +132,16 @@ public class BaseActivity extends AppCompatActivity { } } - private boolean startShell() { - if (Shell.rootAccess()) - return false; - - showAlert(getString(R.string.root_failed)); - return true; - } - void showAlert(final String result) { if (Looper.myLooper() != Looper.getMainLooper()) { runOnUiThread(() -> showAlert(result)); return; } - AlertDialog dialog = new MaterialAlertDialogBuilder(this).setMessage(result).setPositiveButton(android.R.string.ok, null).create(); - dialog.show(); - - TextView txtMessage = dialog - .findViewById(android.R.id.message); - try { - txtMessage.setTextSize(14); - } catch (NullPointerException ignored) { - } + new MaterialAlertDialogBuilder(this) + .setMessage(result) + .setPositiveButton(android.R.string.ok, null) + .show(); } public boolean checkPermissions() { @@ -168,8 +155,10 @@ public class BaseActivity extends AppCompatActivity { } void reboot(String mode) { - if (startShell()) + if (!Shell.rootAccess()) { + showAlert(getString(R.string.root_failed)); return; + } List messages = new LinkedList<>(); diff --git a/app/src/main/java/org/meowcat/edxposed/manager/CrashReportActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/CrashReportActivity.java new file mode 100644 index 00000000..3456bd11 --- /dev/null +++ b/app/src/main/java/org/meowcat/edxposed/manager/CrashReportActivity.java @@ -0,0 +1,120 @@ +package org.meowcat.edxposed.manager; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.material.snackbar.Snackbar; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class CrashReportActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_crash_report); + findViewById(R.id.copyLogs).setOnClickListener(v -> { + ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + //Are there any devices without clipboard...? + if (clipboard != null) { + ClipData clip = ClipData.newPlainText("edcrash", getAllErrorDetailsFromIntent(getIntent())); + clipboard.setPrimaryClip(clip); + Snackbar.make(findViewById(R.id.snackbar), R.string.copy_toast_msg, Snackbar.LENGTH_SHORT).show(); + } + }); + + } + + public String getAllErrorDetailsFromIntent(@NonNull Intent intent) { + Date currentDate = new Date(); + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); + + String buildDateAsString = getBuildDateAsString(dateFormat); + + String versionName = getVersionName(); + + String errorDetails = ""; + + errorDetails += "Build version: " + versionName + " \n"; + if (buildDateAsString != null) { + errorDetails += "Build date: " + buildDateAsString + " \n"; + } + errorDetails += "Current date: " + dateFormat.format(currentDate) + " \n"; + errorDetails += "Device: " + getDeviceModelName() + " \n \n"; + errorDetails += "Stack trace: \n"; + errorDetails += getStackTraceFromIntent(intent); + return errorDetails; + } + + private String getBuildDateAsString(@NonNull DateFormat dateFormat) { + long buildDate; + try { + ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), 0); + ZipFile zf = new ZipFile(ai.sourceDir); + + ZipEntry ze = zf.getEntry("classes.dex"); + buildDate = ze.getTime(); + + + zf.close(); + } catch (Exception e) { + buildDate = 0; + } + + if (buildDate > 312764400000L) { + return dateFormat.format(new Date(buildDate)); + } else { + return null; + } + } + + private String getVersionName() { + try { + PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + return packageInfo.versionName; + } catch (Exception e) { + return "Unknown"; + } + } + + private String getDeviceModelName() { + String manufacturer = Build.MANUFACTURER; + String model = Build.MODEL; + if (model.startsWith(manufacturer)) { + return capitalize(model); + } else { + return capitalize(manufacturer) + " " + model; + } + } + + private String capitalize(@Nullable String s) { + if (s == null || s.length() == 0) { + return ""; + } + char first = s.charAt(0); + if (Character.isUpperCase(first)) { + return s; + } else { + return Character.toUpperCase(first) + s.substring(1); + } + } + + public String getStackTraceFromIntent(@NonNull Intent intent) { + return intent.getStringExtra(BuildConfig.APPLICATION_ID + ".EXTRA_STACK_TRACE"); + } + +} diff --git a/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java index df1ce507..26efef52 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/DownloadActivity.java @@ -102,7 +102,15 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis mListView.setAdapter(mAdapter); mListView.setLayoutManager(new LinearLayoutManager(this)); - mListView.addItemDecoration(new StickyRecyclerHeadersDecoration(mAdapter)); + StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(mAdapter); + mListView.addItemDecoration(headersDecor); + mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + headersDecor.invalidateHeaders(); + } + }); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mListView.getContext(), DividerItemDecoration.VERTICAL); mListView.addItemDecoration(dividerItemDecoration); @@ -171,7 +179,6 @@ public class DownloadActivity extends BaseActivity implements RepoLoader.RepoLis private void reloadItems() { mAdapter.swapCursor(RepoDb.queryModuleOverview(mSortingOrder, mFilterText)); mAdapter.notifyDataSetChanged(); - //mAdapter.getFilter().filter(mFilterText); } @Override diff --git a/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java b/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java index debab8a7..2cee8761 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/DownloadDetailsVersionsFragment.java @@ -1,7 +1,6 @@ package org.meowcat.edxposed.manager; import android.annotation.SuppressLint; -import android.app.Activity; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -41,8 +40,8 @@ import java.util.Date; import static org.meowcat.edxposed.manager.XposedApp.WRITE_EXTERNAL_PERMISSION; public class DownloadDetailsVersionsFragment extends ListFragment { - private DownloadDetailsActivity mActivity; private static View rootView; + private DownloadDetailsActivity mActivity; @Override public void onActivityCreated(Bundle savedInstanceState) { diff --git a/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java b/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java index 76032fce..dcd172a5 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/ModulesActivity.java @@ -1,15 +1,11 @@ package org.meowcat.edxposed.manager; -import android.annotation.SuppressLint; import android.content.ActivityNotFoundException; -import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Color; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -27,9 +23,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.view.menu.MenuBuilder; -import androidx.appcompat.view.menu.MenuPopupHelper; -import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.DividerItemDecoration; @@ -108,6 +101,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi mSwipeRefreshLayout.setRefreshing(false); } }; + private String selectedPackageName; private void filter(String constraint) { filter.filter(constraint); @@ -129,15 +123,12 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi mModuleUtil = ModuleUtil.getInstance(); mPm = getPackageManager(); installedXposedVersion = XposedApp.getXposedVersion(); - if (Build.VERSION.SDK_INT >= 21) { - if (installedXposedVersion <= 0) { - addHeader(); - } - } else { - //if (StatusInstallerFragment.DISABLE_FILE.exists()) installedXposedVersion = -1; - if (installedXposedVersion <= 0) { - addHeader(); - } + if (installedXposedVersion <= 0) { + Snackbar.make(findViewById(R.id.snackbar), R.string.xposed_not_active, Snackbar.LENGTH_LONG).setAction(R.string.Settings, v -> { + Intent intent = new Intent(); + intent.setClass(ModulesActivity.this, SettingsActivity.class); + startActivity(intent); + }).show(); } mAdapter = new ModuleAdapter(); mModuleUtil.addListener(this); @@ -166,12 +157,6 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi } - private void addHeader() { - //View notActiveNote = getLayoutInflater().inflate(R.layout.xposed_not_active_note, mListView, false); - //notActiveNote.setTag(NOT_ACTIVE_NOTE_TAG); - //mListView.addHeaderView(notActiveNote); - } - @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_modules, menu); @@ -277,7 +262,6 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi 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(); @@ -362,78 +346,56 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi runOnUiThread(reloadModules); } - @SuppressLint("RestrictedApi") - private void showMenu(@NonNull Context context, - @NonNull View anchor, - @NonNull ApplicationInfo info) { - PopupMenu appMenu = new PopupMenu(context, anchor); - appMenu.inflate(R.menu.context_menu_modules); - ModuleUtil.InstalledModule installedModule = ModuleUtil.getInstance().getModule(info.packageName); - if (installedModule == null) { - return; + @Override + public boolean onContextItemSelected(MenuItem item) { + ModuleUtil.InstalledModule module = ModuleUtil.getInstance().getModule(selectedPackageName); + if (module == null) { + return false; } - try { - String support = RepoDb - .getModuleSupport(installedModule.packageName); - if (NavUtil.parseURL(support) == null) - appMenu.getMenu().removeItem(R.id.menu_support); - } catch (RepoDb.RowNotFoundException e) { - appMenu.getMenu().removeItem(R.id.menu_download_updates); - appMenu.getMenu().removeItem(R.id.menu_support); + switch (item.getItemId()) { + case R.id.menu_launch: + String packageName = module.packageName; + if (packageName == null) { + return false; + } + Intent launchIntent = getSettingsIntent(packageName); + if (launchIntent != null) { + startActivity(launchIntent); + } else { + Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show(); + } + return true; + + case R.id.menu_download_updates: + Intent detailsIntent = new Intent(this, DownloadDetailsActivity.class); + detailsIntent.setData(Uri.fromParts("package", module.packageName, null)); + startActivity(detailsIntent); + return true; + + case R.id.menu_support: + NavUtil.startURL(this, Uri.parse(RepoDb.getModuleSupport(module.packageName))); + return true; + + case R.id.menu_app_store: + Uri uri = Uri.parse("market://details?id=" + module.packageName); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + startActivity(intent); + } catch (Exception ex) { + ex.printStackTrace(); + } + return true; + + case R.id.menu_app_info: + startActivity(new Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", module.packageName, null))); + return true; + + case R.id.menu_uninstall: + startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, Uri.fromParts("package", module.packageName, null))); + return true; } - appMenu.setOnMenuItemClickListener(menuItem -> { - ModuleUtil.InstalledModule module = ModuleUtil.getInstance().getModule(info.packageName); - if (module == null) { - return false; - } - switch (menuItem.getItemId()) { - case R.id.menu_launch: - String packageName = module.packageName; - if (packageName == null) { - return false; - } - Intent launchIntent = getSettingsIntent(packageName); - if (launchIntent != null) { - startActivity(launchIntent); - } else { - Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show(); - } - return true; - - case R.id.menu_download_updates: - Intent detailsIntent = new Intent(this, DownloadDetailsActivity.class); - detailsIntent.setData(Uri.fromParts("package", module.packageName, null)); - startActivity(detailsIntent); - return true; - - case R.id.menu_support: - NavUtil.startURL(this, Uri.parse(RepoDb.getModuleSupport(module.packageName))); - return true; - - case R.id.menu_app_store: - Uri uri = Uri.parse("market://details?id=" + module.packageName); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - startActivity(intent); - } catch (Exception ex) { - ex.printStackTrace(); - } - return true; - - case R.id.menu_app_info: - startActivity(new Intent(ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", module.packageName, null))); - return true; - - case R.id.menu_uninstall: - startActivity(new Intent(Intent.ACTION_UNINSTALL_PACKAGE, Uri.fromParts("package", module.packageName, null))); - return true; - } - return true; - }); - MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) appMenu.getMenu(), anchor); - menuHelper.setForceShowIcon(true); - menuHelper.show(); + return super.onContextItemSelected(item); } private Intent getSettingsIntent(String packageName) { @@ -458,37 +420,6 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi return intent; } - public void onItemClick(View view) { - if (getFragmentManager() != null) { - try { - showMenu(this, view, Objects.requireNonNull(this).getPackageManager().getApplicationInfo((String) view.getTag(), 0)); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - String packageName = (String) view.getTag(); - if (packageName == null) - return; - - Intent launchIntent = getSettingsIntent(packageName); - if (launchIntent != null) { - startActivity(launchIntent); - } else { - Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show(); - } - } - } else { - String packageName = (String) view.getTag(); - if (packageName == null) { - return; - } - Intent launchIntent = getSettingsIntent(packageName); - if (launchIntent != null) { - startActivity(launchIntent); - } else { - Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show(); - } - } - } - private boolean lowercaseContains(String s, CharSequence filter) { return !TextUtils.isEmpty(s) && s.toLowerCase().contains(filter); } @@ -514,11 +445,41 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - //View view = holder.itemView; ModuleUtil.InstalledModule item = (ModuleUtil.InstalledModule) items.toArray()[position]; - holder.itemView.setOnClickListener(v -> ModulesActivity.this.onItemClick(holder.itemView)); - holder.itemView.setTag(item.packageName); + holder.itemView.setOnClickListener(v -> { + String packageName = item.packageName; + if (packageName == null) { + return; + } + Intent launchIntent = getSettingsIntent(packageName); + if (launchIntent != null) { + startActivity(launchIntent); + } else { + Snackbar.make(findViewById(R.id.snackbar), R.string.module_no_ui, Snackbar.LENGTH_LONG).show(); + } + }); + holder.itemView.setOnLongClickListener(v -> { + selectedPackageName = item.packageName; + return false; + }); + + holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> { + getMenuInflater().inflate(R.menu.context_menu_modules, menu); + ModuleUtil.InstalledModule installedModule = ModuleUtil.getInstance().getModule(item.packageName); + if (installedModule == null) { + return; + } + try { + String support = RepoDb.getModuleSupport(installedModule.packageName); + if (NavUtil.parseURL(support) == null) { + menu.removeItem(R.id.menu_support); + } + } catch (RepoDb.RowNotFoundException e) { + menu.removeItem(R.id.menu_download_updates); + menu.removeItem(R.id.menu_support); + } + }); holder.appName.setText(item.getAppName()); TextView version = holder.appVersion; diff --git a/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java b/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java index 20cd66ad..9ec10f5c 100644 --- a/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java +++ b/app/src/main/java/org/meowcat/edxposed/manager/XposedApp.java @@ -27,6 +27,8 @@ import org.meowcat.edxposed.manager.util.NotificationUtil; import org.meowcat.edxposed.manager.util.RepoLoader; import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.reflect.Method; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -102,6 +104,31 @@ public class XposedApp extends de.robv.android.xposed.installer.XposedApp implem public void onCreate() { super.onCreate(); + try { + Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { + + 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) { + } mInstance = this; mUiThread = Thread.currentThread(); mMainHandler = new Handler(); diff --git a/app/src/main/res/layout/activity_crash_report.xml b/app/src/main/res/layout/activity_crash_report.xml new file mode 100644 index 00000000..f51a21e4 --- /dev/null +++ b/app/src/main/res/layout/activity_crash_report.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_download.xml b/app/src/main/res/layout/activity_download.xml index 5a7a47cf..3e124ffd 100644 --- a/app/src/main/res/layout/activity_download.xml +++ b/app/src/main/res/layout/activity_download.xml @@ -1,5 +1,6 @@ + android:orientation="vertical" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_installer.xml b/app/src/main/res/menu/menu_installer.xml index 322fa8c6..0c6197f4 100644 --- a/app/src/main/res/menu/menu_installer.xml +++ b/app/src/main/res/menu/menu_installer.xml @@ -2,48 +2,51 @@ - + - + - + + + - + - + - + - + - + + + - - - \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b3a30173..fdee50f0 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -296,4 +296,5 @@ 安装于 %1$s \u00b7 更新于 %2$s 兼容模式应用列表 兼容模式 + EdXposed 框架未安装或未激活, 您可在设置中关闭状态检查 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 47dedd22..f8f879ab 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -296,4 +296,5 @@ 安裝於 %1$s \u00b7 更新於 %2$s 兼容模式應用列表 兼容模式 + EdXposed 框架未安裝或未啟用, 您可在設定中關閉狀態檢查 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 8b2ec986..94646a1b 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -296,4 +296,5 @@ 安裝於 %1$s \u00b7 更新於 %2$s 相容模式應用列表 相容模式 + EdXposed 框架未安裝或未啟用, 您可在設定中關閉狀態檢查 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6dbeefaa..90ab83cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -330,4 +330,5 @@ Follow system Compat List Compat mode app list + EdXposed Framework is not currently installed or active\nYou can close status check in settings