diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 200264c69..ec4794b1b 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -342,8 +342,7 @@
-
-
+
diff --git a/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppListFragment.java b/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppListFragment.java
index bf636e1a1..4071af7bd 100644
--- a/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppListFragment.java
+++ b/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppListFragment.java
@@ -5,6 +5,7 @@
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -37,6 +38,7 @@
import com.google.common.io.Files;
import com.miguelcatalan.materialsearchview.MaterialSearchView;
import com.nononsenseapps.filepicker.Utils;
+import com.topjohnwu.superuser.Shell;
import java.io.File;
import java.io.IOException;
@@ -63,12 +65,19 @@
import github.tornaco.android.thanos.databinding.ActivitySmartFreezeAppsBinding;
import github.tornaco.android.thanos.feature.access.AppFeatureManager;
import github.tornaco.android.thanos.picker.AppPickerActivity;
+import github.tornaco.android.thanos.util.DialogUtils;
import github.tornaco.android.thanos.util.IntentUtils;
import github.tornaco.android.thanos.util.ToastUtils;
import github.tornaco.android.thanos.widget.ModernAlertDialog;
import github.tornaco.android.thanos.widget.ModernProgressDialog;
import github.tornaco.permission.requester.RequiresPermission;
import github.tornaco.permission.requester.RuntimePermissions;
+import io.reactivex.Completable;
+import io.reactivex.Scheduler;
+import io.reactivex.functions.Action;
+import io.reactivex.functions.Consumer;
+import io.reactivex.schedulers.Schedulers;
+import rx2.android.schedulers.AndroidSchedulers;
@SuppressWarnings("UnstableApiUsage")
@RuntimePermissions
@@ -105,43 +114,40 @@ private void setupView() {
binding.toolbar.setNavigationIcon(R.drawable.module_common_ic_arrow_back_24dp);
binding.toolbar.setNavigationOnClickListener(v -> requireActivity().onBackPressed());
// Search.
- binding.searchView.setOnQueryTextListener(
- new MaterialSearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String query) {
- viewModel.setSearchText(query);
- return true;
- }
+ binding.searchView.setOnQueryTextListener(new MaterialSearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ viewModel.setSearchText(query);
+ return true;
+ }
- @Override
- public boolean onQueryTextChange(String newText) {
- viewModel.setSearchText(newText);
- return true;
- }
- });
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ viewModel.setSearchText(newText);
+ return true;
+ }
+ });
- binding.searchView.setOnSearchViewListener(
- new MaterialSearchView.SearchViewListener() {
- @Override
- public void onSearchViewShown() {
- binding.toolbarLayout.setTitleEnabled(false);
- binding.appbar.setExpanded(false, true);
- }
+ binding.searchView.setOnSearchViewListener(new MaterialSearchView.SearchViewListener() {
+ @Override
+ public void onSearchViewShown() {
+ binding.toolbarLayout.setTitleEnabled(false);
+ binding.appbar.setExpanded(false, true);
+ }
- @Override
- public void onSearchViewClosed() {
- viewModel.clearSearchText();
- binding.toolbarLayout.setTitleEnabled(true);
- }
- });
+ @Override
+ public void onSearchViewClosed() {
+ viewModel.clearSearchText();
+ binding.toolbarLayout.setTitleEnabled(true);
+ }
+ });
// List.
binding.apps.setLayoutManager(new GridLayoutManager(requireContext(), 5));
binding.apps.setAdapter(new SmartFreezeAppsAdapter(new AppItemActionListener() {
@Override
public void onAppItemClick(AppInfo appInfo) {
- PackageManager pm = ThanosManager.from(requireContext())
- .getPkgManager();
+ PackageManager pm = ThanosManager.from(requireContext()).getPkgManager();
pm.launchSmartFreezePkg(Pkg.fromAppInfo(appInfo));
appInfo.setState(AppInfo.STATE_ENABLED);
}
@@ -170,20 +176,14 @@ protected void onSetupSorter(Chip sorterAnchor) {
menuPopupHelper.setForceShowIcon(true);
int reverseItemId = 10086;
- MenuItem reverseItem = menuBuilder.add(1000,
- reverseItemId,
- Menu.NONE,
- github.tornaco.android.thanos.module.common.R.string.common_sort_reverse);
+ MenuItem reverseItem = menuBuilder.add(1000, reverseItemId, Menu.NONE, github.tornaco.android.thanos.module.common.R.string.common_sort_reverse);
reverseItem.setCheckable(true);
reverseItem.setChecked(viewModel.isSortReverse());
reverseItem.setIcon(github.tornaco.android.thanos.module.common.R.drawable.module_common_ic_arrow_up_down_line);
for (int i = 0; i < appSortArray.length; i++) {
AppSort sort = appSortArray[i];
- MenuItem sortItem = menuBuilder.add(1000,
- i,
- Menu.NONE,
- sort.labelRes);
+ MenuItem sortItem = menuBuilder.add(1000, i, Menu.NONE, sort.labelRes);
boolean isSelected = viewModel.getCurrentAppSort() == sort;
if (isSelected) {
sortItem.setTitle(getString(sort.labelRes) + " \uD83C\uDFAF");
@@ -287,50 +287,41 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
postOnUiDelayed(() -> viewModel.start(), 100);
}
- private final ActivityResultLauncher pickApps
- = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null && result.getData().hasExtra("apps")) {
- List appInfos = result.getData().getParcelableArrayListExtra("apps");
- PackageSet packageSet = viewModel.getPackageSet();
- if (packageSet == null) return;
- if (packageSet.isPrebuilt()) {
- onRequestAddToSmartFreezeList(appInfos, false);
- } else {
- onRequestAddToSmartFreezeListAskIfAddToPkgSet(appInfos);
- }
- }
- });
-
- private final ActivityResultLauncher chooseFileExportPackageListQBelow
- = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
- // Use the provided utility method to parse the result
- List files = Utils.getSelectedFilesFromResult(result.getData());
- File file = Utils.getFileForUri(files.get(0));
- doExportPackageListChooseFileQBelow(file);
- }
- });
+ private final ActivityResultLauncher pickApps = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
+ if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null && result.getData().hasExtra("apps")) {
+ List appInfos = result.getData().getParcelableArrayListExtra("apps");
+ PackageSet packageSet = viewModel.getPackageSet();
+ if (packageSet == null) return;
+ if (packageSet.isPrebuilt()) {
+ onRequestAddToSmartFreezeList(appInfos, false);
+ } else {
+ onRequestAddToSmartFreezeListAskIfAddToPkgSet(appInfos);
+ }
+ }
+ });
+
+ private final ActivityResultLauncher chooseFileExportPackageListQBelow = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
+ if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
+ // Use the provided utility method to parse the result
+ List files = Utils.getSelectedFilesFromResult(result.getData());
+ File file = Utils.getFileForUri(files.get(0));
+ doExportPackageListChooseFileQBelow(file);
+ }
+ });
- private final ActivityResultLauncher chooseFileExportPackageListQAndAbove
- = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
- doExportPackageListChooseFileQAndAbove(result.getData());
- }
- });
+ private final ActivityResultLauncher chooseFileExportPackageListQAndAbove = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
+ if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
+ doExportPackageListChooseFileQAndAbove(result.getData());
+ }
+ });
private void onRequestAddToSmartFreezeList(List appInfos, boolean alsoAddToPkgSet) {
ModernProgressDialog progress = new ModernProgressDialog(requireActivity());
progress.setTitle(R.string.common_text_wait_a_moment);
- viewModel.addToSmartFreezeList(appInfos,
- alsoAddToPkgSet,
- appInfo -> runOnUiThread(() -> progress.setMessage(appInfo.getAppLabel())),
- success -> {
- progress.dismiss();
- viewModel.start();
- });
+ viewModel.addToSmartFreezeList(appInfos, alsoAddToPkgSet, appInfo -> runOnUiThread(() -> progress.setMessage(appInfo.getAppLabel())), success -> {
+ progress.dismiss();
+ viewModel.start();
+ });
progress.show();
}
@@ -366,14 +357,9 @@ private boolean handleOptionsItemSelected(@NonNull MenuItem item) {
if (R.id.action_enable_all_smart_freeze == item.getItemId()) {
AppFeatureManager.INSTANCE.withSubscriptionStatus(requireContext(), isSubscribed -> {
if (isSubscribed) {
- new MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.menu_title_smart_app_freeze_enable_all_smart_freeze_apps)
- .setMessage(R.string.menu_desc_smart_app_freeze_enable_all_smart_freeze_apps)
- .setPositiveButton(android.R.string.ok, (dialog, which) -> {
- onRequestEnableAllSmartFreezeApps();
- })
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ new MaterialAlertDialogBuilder(requireActivity()).setTitle(R.string.menu_title_smart_app_freeze_enable_all_smart_freeze_apps).setMessage(R.string.menu_desc_smart_app_freeze_enable_all_smart_freeze_apps).setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ onRequestEnableAllSmartFreezeApps();
+ }).setNegativeButton(android.R.string.cancel, null).show();
} else {
AppFeatureManager.INSTANCE.showDonateIntroDialog(requireActivity());
}
@@ -384,14 +370,9 @@ private boolean handleOptionsItemSelected(@NonNull MenuItem item) {
if (R.id.action_enable_all_smart_freeze_temp == item.getItemId()) {
AppFeatureManager.INSTANCE.withSubscriptionStatus(requireContext(), isSubscribed -> {
if (isSubscribed) {
- new MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.menu_title_smart_app_freeze_enable_all_apps_smart_freeze_temp)
- .setMessage(R.string.menu_desc_smart_app_freeze_enable_all_apps_smart_freeze_temp)
- .setPositiveButton(android.R.string.ok, (dialog, which) -> {
- onRequestEnableAllSmartFreezeAppsTemp();
- })
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ new MaterialAlertDialogBuilder(requireActivity()).setTitle(R.string.menu_title_smart_app_freeze_enable_all_apps_smart_freeze_temp).setMessage(R.string.menu_desc_smart_app_freeze_enable_all_apps_smart_freeze_temp).setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ onRequestEnableAllSmartFreezeAppsTemp();
+ }).setNegativeButton(android.R.string.cancel, null).show();
} else {
AppFeatureManager.INSTANCE.showDonateIntroDialog(requireActivity());
}
@@ -402,14 +383,9 @@ private boolean handleOptionsItemSelected(@NonNull MenuItem item) {
if (R.id.action_enable_all_apps == item.getItemId()) {
AppFeatureManager.INSTANCE.withSubscriptionStatus(requireContext(), isSubscribed -> {
if (isSubscribed) {
- new MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.menu_title_smart_app_freeze_enable_all_apps)
- .setMessage(R.string.menu_desc_smart_app_freeze_enable_all_apps)
- .setPositiveButton(android.R.string.ok, (dialog, which) -> {
- onRequestEnableAllApps();
- })
- .setNegativeButton(android.R.string.cancel, null)
- .show();
+ new MaterialAlertDialogBuilder(requireActivity()).setTitle(R.string.menu_title_smart_app_freeze_enable_all_apps).setMessage(R.string.menu_desc_smart_app_freeze_enable_all_apps).setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ onRequestEnableAllApps();
+ }).setNegativeButton(android.R.string.cancel, null).show();
} else {
AppFeatureManager.INSTANCE.showDonateIntroDialog(requireActivity());
}
@@ -448,29 +424,22 @@ private boolean handleOptionsItemSelected(@NonNull MenuItem item) {
private void onRequestImportPackageList() {
String[] items = getResources().getStringArray(R.array.module_common_import_selections);
- AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.menu_title_smart_app_freeze_import_package_list)
- .setSingleChoiceItems(items, -1,
- (d, which) -> {
- d.dismiss();
- if (which == 0) {
- onRequestImportPackageListFromClipBoard();
- } else {
- if (OsUtils.isTOrAbove()) {
- SmartFreezeAppListFragmentPermissionRequester.onRequestImportPackageListFromFileTOrAboveChecked(this);
- } else {
- SmartFreezeAppListFragmentPermissionRequester.onRequestImportPackageListFromFileTBelowChecked(this);
- }
- }
- }).create();
+ AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity()).setTitle(R.string.menu_title_smart_app_freeze_import_package_list).setSingleChoiceItems(items, -1, (d, which) -> {
+ d.dismiss();
+ if (which == 0) {
+ onRequestImportPackageListFromClipBoard();
+ } else {
+ if (OsUtils.isTOrAbove()) {
+ SmartFreezeAppListFragmentPermissionRequester.onRequestImportPackageListFromFileTOrAboveChecked(this);
+ } else {
+ SmartFreezeAppListFragmentPermissionRequester.onRequestImportPackageListFromFileTBelowChecked(this);
+ }
+ }
+ }).create();
dialog.show();
}
- @RequiresPermission({
- Manifest.permission.READ_MEDIA_IMAGES,
- Manifest.permission.READ_MEDIA_AUDIO,
- Manifest.permission.READ_MEDIA_VIDEO,
- })
+ @RequiresPermission({Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_VIDEO,})
void onRequestImportPackageListFromFileTOrAbove() {
IntentUtils.startFilePickerActivityForRes(this, REQUEST_CODE_PICK_IMPORT_PATH);
}
@@ -506,21 +475,18 @@ private void onRequestImportPackageListFromClipBoard() {
private void onRequestExportPackageList() {
String[] items = getResources().getStringArray(R.array.module_common_export_selections);
- AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.menu_title_smart_app_freeze_export_package_list)
- .setSingleChoiceItems(items, -1,
- (d, which) -> {
- d.dismiss();
- if (which == 0) {
- onRequestExportPackageListToClipBoard();
- } else {
- if (OsUtils.isTOrAbove()) {
- SmartFreezeAppListFragmentPermissionRequester.onRequestExportPackageListChooseFileTOrAboveChecked(this);
- } else {
- SmartFreezeAppListFragmentPermissionRequester.onRequestExportPackageListChooseFileTBelowChecked(this);
- }
- }
- }).create();
+ AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity()).setTitle(R.string.menu_title_smart_app_freeze_export_package_list).setSingleChoiceItems(items, -1, (d, which) -> {
+ d.dismiss();
+ if (which == 0) {
+ onRequestExportPackageListToClipBoard();
+ } else {
+ if (OsUtils.isTOrAbove()) {
+ SmartFreezeAppListFragmentPermissionRequester.onRequestExportPackageListChooseFileTOrAboveChecked(this);
+ } else {
+ SmartFreezeAppListFragmentPermissionRequester.onRequestExportPackageListChooseFileTBelowChecked(this);
+ }
+ }
+ }).create();
dialog.show();
}
@@ -531,11 +497,7 @@ private void onRequestExportPackageListToClipBoard() {
});
}
- @RequiresPermission({
- Manifest.permission.READ_MEDIA_IMAGES,
- Manifest.permission.READ_MEDIA_AUDIO,
- Manifest.permission.READ_MEDIA_VIDEO,
- })
+ @RequiresPermission({Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_VIDEO,})
void onRequestExportPackageListChooseFileTOrAbove() {
onRequestExportPackageListChooseFileQAndAbove();
}
@@ -571,9 +533,7 @@ private void doExportPackageListChooseFileQBelow(File file) {
File expFile = new File(file, expFileNameWithExt);
Files.createParentDirs(expFile);
OutputStream os = Files.asByteSink(expFile).openStream();
- viewModel.exportPackageListToFile(os,
- () -> ToastUtils.ok(requireActivity()),
- throwable -> Toast.makeText(requireActivity(), Log.getStackTraceString(throwable), Toast.LENGTH_LONG).show());
+ viewModel.exportPackageListToFile(os, () -> ToastUtils.ok(requireActivity()), throwable -> Toast.makeText(requireActivity(), Log.getStackTraceString(throwable), Toast.LENGTH_LONG).show());
} catch (Throwable e) {
XLog.e("doExportPackageListChooseFileQBelow error", e);
Toast.makeText(requireActivity(), Log.getStackTraceString(e), Toast.LENGTH_LONG).show();
@@ -597,9 +557,7 @@ private void doExportPackageListChooseFileQAndAbove(Intent data) {
XLog.d("doExportPackageListChooseFileQAndAbove, fileUri == %s", fileUri);
try {
OutputStream os = Objects.requireNonNull(requireContext()).getContentResolver().openOutputStream(fileUri);
- viewModel.exportPackageListToFile(os,
- () -> ToastUtils.ok(requireActivity()),
- throwable -> Toast.makeText(requireActivity(), Log.getStackTraceString(throwable), Toast.LENGTH_LONG).show());
+ viewModel.exportPackageListToFile(os, () -> ToastUtils.ok(requireActivity()), throwable -> Toast.makeText(requireActivity(), Log.getStackTraceString(throwable), Toast.LENGTH_LONG).show());
} catch (IOException e) {
XLog.e(e);
Toast.makeText(requireContext(), Log.getStackTraceString(e), Toast.LENGTH_LONG).show();
@@ -646,8 +604,7 @@ void onRequestShortcutStubApk(AppInfo appInfo) {
Objects.requireNonNull(appVersionNameView).setText(appInfo.getVersionName());
new MaterialAlertDialogBuilder(requireActivity())
- .setView(dialogView)
- .setTitle(R.string.menu_title_create_shortcut_apk)
+ .setView(dialogView).setTitle(R.string.menu_title_create_shortcut_apk)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
String appName = appNameView.getText().toString();
@@ -657,10 +614,46 @@ void onRequestShortcutStubApk(AppInfo appInfo) {
appVersionCode = Integer.parseInt(appVersionCodeView.getText().toString());
} catch (NumberFormatException ignored) {
}
- viewModel.createShortcutStubApkForAsync(appInfo, appName, appVersionName, appVersionCode);
+ viewModel.createShortcutStubApkForAsync(appInfo, appName, appVersionName, appVersionCode, file -> onShortcutApkReady(appInfo, file));
}).show();
}
+ @SuppressLint("CheckResult")
+ private void onShortcutApkReady(AppInfo appInfo, File apkFile) {
+ new MaterialAlertDialogBuilder(requireActivity())
+ .setTitle(R.string.menu_title_create_shortcut_apk)
+ .setMessage(appInfo.getAppLabel() + "\n" + apkFile.getAbsolutePath())
+ .setNegativeButton(android.R.string.cancel, null)
+ .setNeutralButton("SILENT INSTALL", (dialog, which) -> {
+ ModernProgressDialog progressDialog = new ModernProgressDialog(requireActivity());
+ progressDialog.setMessage(getString(R.string.common_text_wait_a_moment));
+ progressDialog.show();
+ Completable.fromRunnable(() -> {
+ File tmpFile = new File("/data/local/tmp/" + appInfo.getPkgName() + "_proxy.apk");
+ Shell.su("cp " + apkFile.getAbsolutePath() + " " + tmpFile.getAbsolutePath()).exec();
+ XLog.w("apk path: " + tmpFile.getAbsolutePath());
+ Shell.su("pm install " + tmpFile.getAbsolutePath()).exec();
+ Shell.su("rm " + tmpFile.getAbsolutePath()).exec();
+ }).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Action() {
+ @Override
+ public void run() throws Exception {
+ progressDialog.dismiss();
+ }
+ }, new Consumer() {
+ @Override
+ public void accept(Throwable e) throws Exception {
+ DialogUtils.showError(requireActivity(), e);
+ XLog.e("onShortcutApkReady error", e);
+ progressDialog.dismiss();
+ }
+ });
+ })
+ .setPositiveButton(R.string.title_install, (dialog, which) ->
+ viewModel.requestInstallStubApk(requireContext(), apkFile)).show();
+ }
+
@Override
public boolean onBackPressed() {
return closeSearch();
@@ -708,8 +701,7 @@ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent d
}
public static SmartFreezeAppsViewModel obtainViewModel(FragmentActivity activity) {
- ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory
- .getInstance(activity.getApplication());
+ ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(activity.getApplication());
return ViewModelProviders.of(activity, factory).get(SmartFreezeAppsViewModel.class);
}
}
diff --git a/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppsViewModel.java b/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppsViewModel.java
index 0d25d8634..d66d3b906 100644
--- a/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppsViewModel.java
+++ b/android/app/src/main/java/github/tornaco/android/thanos/power/SmartFreezeAppsViewModel.java
@@ -161,14 +161,20 @@ private void inflateAppUsageStats(List res) {
}
}
- void createShortcutStubApkForAsync(AppInfo appInfo, String appLabel, String versionName, int versionCode) {
- disposables.add(Single.create((SingleOnSubscribe) emitter -> emitter.onSuccess(ShortcutHelper.createShortcutStubApkFor(getApplication(), appInfo, appLabel, versionName, versionCode))).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(file -> requestInstallStubApk(getApplication(), file), throwable -> {
- XLog.e("createShortcutStubApkForAsync error", throwable);
- Toast.makeText(getApplication(), throwable.getMessage(), Toast.LENGTH_LONG).show();
- }));
+ void createShortcutStubApkForAsync(AppInfo appInfo, String appLabel, String versionName, int versionCode, Consumer onApkFileReady) {
+ disposables.add(Single.create((SingleOnSubscribe) emitter ->
+ emitter.onSuccess(ShortcutHelper.createShortcutStubApkFor(getApplication(), appInfo, appLabel, versionName, versionCode)))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(file -> {
+ onApkFileReady.accept(file);
+ }, throwable -> {
+ XLog.e("createShortcutStubApkForAsync error", throwable);
+ Toast.makeText(getApplication(), throwable.getMessage(), Toast.LENGTH_LONG).show();
+ }));
}
- private void requestInstallStubApk(Context context, File apk) {
+ public void requestInstallStubApk(Context context, File apk) {
InstallerUtils.installUserAppWithIntent(context, apk);
}
diff --git a/android/app/src/prc/AndroidManifest.xml b/android/app/src/prc/AndroidManifest.xml
new file mode 100644
index 000000000..c756a4644
--- /dev/null
+++ b/android/app/src/prc/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file