use of io.github.muntashirakon.AppManager.apk.ApkFile in project AppManager by MuntashirAkon.
the class AppExplorerViewModel method loadFiles.
@AnyThread
public void loadFiles(@Nullable Uri uri) {
executor.submit(() -> {
if (apkFile == null) {
try {
int key = ApkFile.createInstance(apkUri, null);
apkFile = ApkFile.getInstance(key);
ApkFile.Entry baseEntry = apkFile.getBaseEntry();
File cachedFile = baseEntry.getRealCachedFile();
cachedFiles.add(cachedFile);
int vfsId = VirtualFileSystem.mount(new VirtualFileSystem.ZipFileSystem(apkUri, cachedFile));
vfsIds.add(vfsId);
zipFileRoot = VirtualFileSystem.getFsRoot(vfsId);
} catch (Throwable e) {
e.printStackTrace();
this.fmItems.postValue(Collections.emptyList());
return;
}
}
List<AdapterItem> adapterItems = new ArrayList<>();
try {
Path path;
if (uri == null) {
// Null URI always means root of the zip file
path = zipFileRoot;
} else {
path = new Path(AppManager.getContext(), uri);
}
for (Path child : path.listFiles()) {
adapterItems.add(new AdapterItem(child));
}
Collections.sort(adapterItems);
} catch (Exception e) {
e.printStackTrace();
} finally {
this.fmItems.postValue(adapterItems);
}
});
}
use of io.github.muntashirakon.AppManager.apk.ApkFile in project AppManager by MuntashirAkon.
the class PackageInstallerCompat method install.
public boolean install(@NonNull ApkFile apkFile) {
try {
this.apkFile = apkFile;
this.packageName = apkFile.getPackageName();
initBroadcastReceiver();
new Thread(this::copyObb).start();
Log.d(TAG, "Install: opening session...");
if (!openSession())
return false;
List<ApkFile.Entry> selectedEntries = apkFile.getSelectedEntries();
Log.d(TAG, "Install: selected entries: " + selectedEntries.size());
// Write apk files
for (ApkFile.Entry entry : selectedEntries) {
try (InputStream apkInputStream = entry.getSignedInputStream(context);
OutputStream apkOutputStream = session.openWrite(entry.getFileName(), 0, entry.getFileSize())) {
IoUtils.copy(apkInputStream, apkOutputStream);
session.fsync(apkOutputStream);
Log.d(TAG, "Install: copied entry " + entry.name);
} catch (IOException e) {
callFinish(STATUS_FAILURE_SESSION_WRITE);
Log.e(TAG, "Install: Cannot copy files to session.", e);
return abandon();
} catch (SecurityException e) {
callFinish(STATUS_FAILURE_SECURITY);
Log.e(TAG, "Install: Cannot access apk files.", e);
return abandon();
}
}
Log.d(TAG, "Install: Running installation...");
return commit();
} finally {
unregisterReceiver();
}
}
use of io.github.muntashirakon.AppManager.apk.ApkFile in project AppManager by MuntashirAkon.
the class SplitApkChooser method onCreateDialog.
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
int apkFileKey = requireArguments().getInt(EXTRA_APK_FILE_KEY, -1);
String actionName = requireArguments().getString(EXTRA_ACTION_NAME);
ApplicationInfo appInfo = requireArguments().getParcelable(EXTRA_APP_INFO);
String versionInfo = requireArguments().getString(EXTRA_VERSION_INFO);
pm = requireActivity().getPackageManager();
if (apkFileKey == -1 || appInfo == null) {
throw new IllegalArgumentException("ApkFile cannot be empty.");
}
apkFile = ApkFile.getInstance(apkFileKey);
if (!apkFile.isSplit())
throw new RuntimeException("Apk file does not contain any split.");
List<ApkFile.Entry> apkEntries = apkFile.getEntries();
CharSequence[] entryNames = new CharSequence[apkEntries.size()];
final boolean[] choices = getChoices(apkEntries);
for (int i = 0; i < apkEntries.size(); ++i) {
entryNames[i] = apkEntries.get(i).toLocalizedString(requireActivity());
}
if (installInterface == null)
throw new RuntimeException("No install action has been set.");
return new MaterialAlertDialogBuilder(requireActivity()).setCancelable(false).setCustomTitle(UIUtils.getDialogTitle(requireActivity(), pm.getApplicationLabel(appInfo), pm.getApplicationIcon(appInfo), versionInfo)).setMultiChoiceItems(entryNames, choices, (dialog, which, isChecked) -> {
if (isChecked)
apkFile.select(which);
else
apkFile.deselect(which);
}).setPositiveButton(actionName == null ? getString(R.string.install) : actionName, (dialog, which) -> installInterface.triggerInstall()).setNegativeButton(R.string.cancel, (dialog, which) -> dialog.cancel()).create();
}
use of io.github.muntashirakon.AppManager.apk.ApkFile in project AppManager by MuntashirAkon.
the class AppInfoFragment method setupTagCloud.
@UiThread
private void setupTagCloud(AppInfoViewModel.TagCloud tagCloud) {
mTagCloud.removeAllViews();
if (mainModel == null)
return;
// Add tracker chip
if (!tagCloud.trackerComponents.isEmpty()) {
CharSequence[] trackerComponentNames = new CharSequence[tagCloud.trackerComponents.size()];
for (int i = 0; i < trackerComponentNames.length; ++i) {
ComponentRule rule = tagCloud.trackerComponents.get(i);
trackerComponentNames[i] = rule.isBlocked() ? getColoredText(rule.name, ContextCompat.getColor(mActivity, R.color.stopped)) : rule.name;
}
addChip(getResources().getQuantityString(R.plurals.no_of_trackers, tagCloud.trackerComponents.size(), tagCloud.trackerComponents.size()), tagCloud.areAllTrackersBlocked ? R.color.stopped : R.color.tracker).setOnClickListener(v -> {
if (!isExternalApk && isRootEnabled) {
new SearchableMultiChoiceDialogBuilder<>(mActivity, tagCloud.trackerComponents, trackerComponentNames).setTitle(R.string.trackers).setSelections(tagCloud.trackerComponents).setNegativeButton(R.string.cancel, null).setPositiveButton(R.string.block, (dialog, which, selectedItems) -> {
showProgressIndicator(true);
executor.submit(() -> {
mainModel.addRules(selectedItems, true);
runOnUiThread(() -> {
if (isDetached())
return;
showProgressIndicator(false);
displayShortToast(R.string.done);
});
});
}).setNeutralButton(R.string.unblock, (dialog, which, selectedItems) -> {
showProgressIndicator(true);
executor.submit(() -> {
mainModel.removeRules(selectedItems, true);
runOnUiThread(() -> {
if (isDetached())
return;
showProgressIndicator(false);
displayShortToast(R.string.done);
});
});
}).show();
} else {
new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.trackers).setItems(trackerComponentNames, null).setNegativeButton(R.string.close, null).show();
}
});
}
if (tagCloud.isSystemApp) {
if (tagCloud.isSystemlessPath) {
addChip(R.string.systemless_app);
} else
addChip(R.string.system_app);
if (tagCloud.isUpdatedSystemApp) {
addChip(R.string.updated_app);
}
} else if (!mainModel.getIsExternalApk())
addChip(R.string.user_app);
if (tagCloud.splitCount > 0) {
addChip(getResources().getQuantityString(R.plurals.no_of_splits, tagCloud.splitCount, tagCloud.splitCount)).setOnClickListener(v -> {
try (ApkFile apkFile = ApkFile.getInstance(mainModel.getApkFileKey())) {
// Display a list of apks
List<ApkFile.Entry> apkEntries = apkFile.getEntries();
CharSequence[] entryNames = new CharSequence[tagCloud.splitCount];
for (int i = 0; i < tagCloud.splitCount; ++i) {
entryNames[i] = apkEntries.get(i + 1).toLocalizedString(mActivity);
}
new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.splits).setItems(entryNames, null).setNegativeButton(R.string.close, null).show();
}
});
}
if (tagCloud.isDebuggable) {
addChip(R.string.debuggable);
}
if (tagCloud.isTestOnly) {
addChip(R.string.test_only);
}
if (!tagCloud.hasCode) {
addChip(R.string.no_code);
}
if (tagCloud.hasRequestedLargeHeap) {
addChip(R.string.requested_large_heap, R.color.tracker);
}
if (tagCloud.runningServices.size() > 0) {
addChip(R.string.running, R.color.running).setOnClickListener(v -> {
mProgressIndicator.show();
executor.submit(() -> {
CharSequence[] runningServices = new CharSequence[tagCloud.runningServices.size()];
for (int i = 0; i < runningServices.length; ++i) {
runningServices[i] = new SpannableStringBuilder().append(getTitleText(mActivity, tagCloud.runningServices.get(i).service.getShortClassName())).append("\n").append(getSmallerText(new SpannableStringBuilder().append(getStyledKeyValue(mActivity, R.string.process_name, tagCloud.runningServices.get(i).process)).append("\n").append(getStyledKeyValue(mActivity, R.string.pid, String.valueOf(tagCloud.runningServices.get(i).pid)))));
}
DialogTitleBuilder titleBuilder = new DialogTitleBuilder(mActivity).setTitle(R.string.running_services);
if (PermissionUtils.hasDumpPermission() && FeatureController.isLogViewerEnabled()) {
titleBuilder.setSubtitle(R.string.running_services_logcat_hint);
}
runOnUiThread(() -> {
mProgressIndicator.hide();
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mActivity).setCustomTitle(titleBuilder.build()).setItems(runningServices, (dialog, which) -> {
if (!FeatureController.isLogViewerEnabled())
return;
Intent logViewerIntent = new Intent(mActivity.getApplicationContext(), LogViewerActivity.class).setAction(LogViewerActivity.ACTION_LAUNCH).putExtra(LogViewerActivity.EXTRA_FILTER, SearchCriteria.PID_KEYWORD + tagCloud.runningServices.get(which).pid).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mActivity.startActivity(logViewerIntent);
}).setNeutralButton(R.string.force_stop, (dialog, which) -> executor.submit(() -> {
try {
PackageManagerCompat.forceStopPackage(mPackageName, mainModel.getUserHandle());
runOnUiThread(this::refreshDetails);
} catch (RemoteException | SecurityException e) {
Log.e(TAG, e);
displayLongToast(R.string.failed_to_stop, mPackageLabel);
}
})).setNegativeButton(R.string.close, null);
builder.show();
});
});
});
}
if (tagCloud.isForceStopped) {
addChip(R.string.stopped, R.color.stopped);
}
if (!tagCloud.isAppEnabled) {
addChip(R.string.disabled_app, R.color.disabled_user);
}
if (tagCloud.isAppSuspended) {
addChip(R.string.suspended, R.color.stopped);
}
if (tagCloud.isAppHidden) {
addChip(R.string.hidden, R.color.disabled_user);
}
magiskHiddenProcesses = tagCloud.magiskHiddenProcesses;
if (tagCloud.isMagiskHideEnabled) {
addChip(R.string.magisk_hide_enabled).setOnClickListener(v -> displayMagiskHideDialog());
}
magiskDeniedProcesses = tagCloud.magiskDeniedProcesses;
if (tagCloud.isMagiskDenyListEnabled) {
addChip(R.string.magisk_denylist).setOnClickListener(v -> displayMagiskDenyListDialog());
}
if (tagCloud.hasKeyStoreItems) {
Chip chip;
if (tagCloud.hasMasterKeyInKeyStore) {
chip = addChip(R.string.keystore, R.color.tracker);
} else
chip = addChip(R.string.keystore);
chip.setOnClickListener(view -> new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.keystore).setItems(KeyStoreUtils.getKeyStoreFiles(mApplicationInfo.uid, mainModel.getUserHandle()).toArray(new String[0]), null).setNegativeButton(R.string.close, null).show());
}
if (tagCloud.backups.length > 0) {
CharSequence[] backupNames = new CharSequence[tagCloud.backups.length];
for (int i = 0; i < tagCloud.backups.length; ++i) {
backupNames[i] = tagCloud.backups[i].toLocalizedString(mActivity);
}
addChip(R.string.backup).setOnClickListener(v -> new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.backup).setItems(backupNames, null).setNegativeButton(R.string.close, null).show());
}
if (!tagCloud.isBatteryOptimized) {
addChip(R.string.no_battery_optimization, R.color.red_orange).setOnClickListener(v -> new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.battery_optimization).setMessage(R.string.enable_battery_optimization).setNegativeButton(R.string.no, null).setPositiveButton(R.string.yes, (dialog, which) -> {
Runner.runCommand(new String[] { "dumpsys", "deviceidle", "whitelist", "-" + mPackageName });
refreshDetails();
}).show());
}
if (tagCloud.netPolicies > 0) {
String[] readablePolicies = NetworkPolicyManagerCompat.getReadablePolicies(mActivity, tagCloud.netPolicies).values().toArray(new String[0]);
addChip(R.string.has_net_policy).setOnClickListener(v -> new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.net_policy).setItems(readablePolicies, null).setNegativeButton(R.string.ok, null).show());
}
if (tagCloud.ssaid != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
addChip(R.string.ssaid, R.color.red_orange).setOnClickListener(v -> {
View view = getLayoutInflater().inflate(R.layout.dialog_ssaid_info, null);
AlertDialog alertDialog = new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.ssaid).setView(view).setPositiveButton(R.string.apply, null).setNegativeButton(R.string.close, null).setNeutralButton(R.string.reset_to_default, null).create();
TextInputEditText ssaidHolder = view.findViewById(R.id.ssaid);
TextInputLayout ssaidInputLayout = view.findViewById(android.R.id.text1);
AtomicReference<Button> applyButton = new AtomicReference<>();
AtomicReference<Button> resetButton = new AtomicReference<>();
AtomicReference<String> ssaid = new AtomicReference<>(tagCloud.ssaid);
alertDialog.setOnShowListener(dialog -> {
applyButton.set(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE));
resetButton.set(alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL));
applyButton.get().setVisibility(View.GONE);
applyButton.get().setOnClickListener(v2 -> executor.submit(() -> {
try {
SsaidSettings ssaidSettings = new SsaidSettings(mPackageName, mApplicationInfo.uid);
if (ssaidSettings.setSsaid(ssaid.get())) {
model.loadTagCloud();
runOnUiThread(() -> displayLongToast(R.string.restart_to_reflect_changes));
} else {
runOnUiThread(() -> displayLongToast(R.string.failed_to_change_ssaid));
}
alertDialog.dismiss();
} catch (IOException ignore) {
}
}));
resetButton.get().setVisibility(View.GONE);
resetButton.get().setOnClickListener(v2 -> {
ssaid.set(tagCloud.ssaid);
ssaidHolder.setText(ssaid.get());
resetButton.get().setVisibility(View.GONE);
applyButton.get().setVisibility(View.GONE);
});
});
ssaidHolder.setText(tagCloud.ssaid);
ssaidHolder.setTypeface(Typeface.MONOSPACE);
ssaidHolder.setOnClickListener(v2 -> {
ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("SSAID", ssaid.get());
clipboard.setPrimaryClip(clip);
displayShortToast(R.string.copied_to_clipboard);
});
ssaidInputLayout.setEndIconOnClickListener(v2 -> {
ssaid.set(SsaidSettings.generateSsaid(mPackageName));
ssaidHolder.setText(ssaid.get());
if (!tagCloud.ssaid.equals(ssaid.get())) {
if (resetButton.get() != null) {
resetButton.get().setVisibility(View.VISIBLE);
}
if (applyButton.get() != null) {
applyButton.get().setVisibility(View.VISIBLE);
}
}
});
alertDialog.show();
});
}
if (tagCloud.uriGrants != null) {
addChip(R.string.saf).setOnClickListener(v -> {
CharSequence[] uriGrants = new CharSequence[tagCloud.uriGrants.size()];
for (int i = 0; i < tagCloud.uriGrants.size(); ++i) {
uriGrants[i] = tagCloud.uriGrants.get(i).uri.toString();
}
new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.saf).setItems(uriGrants, null).setNegativeButton(R.string.close, null).show();
});
}
if (tagCloud.usesPlayAppSigning) {
addChip(R.string.uses_play_app_signing, R.color.disabled_user).setOnClickListener(v -> new MaterialAlertDialogBuilder(mActivity).setTitle(R.string.uses_play_app_signing).setMessage(R.string.uses_play_app_signing_description).setNegativeButton(R.string.close, null).show());
}
}
use of io.github.muntashirakon.AppManager.apk.ApkFile in project AppManager by MuntashirAkon.
the class AppExplorerViewModel method onCleared.
@Override
protected void onCleared() {
super.onCleared();
executor.shutdownNow();
// Unmount file systems
for (int vsfId : vfsIds) {
try {
VirtualFileSystem.unmount(vsfId);
} catch (Throwable e) {
e.printStackTrace();
}
}
FileUtils.closeQuietly(apkFile);
for (File cachedFile : cachedFiles) {
FileUtils.deleteSilently(cachedFile);
}
}
Aggregations