Input:
import android.app.Activity;
import android.content.ClipData;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.appcompat.widget.PopupMenu;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.threethan.questpatcher.R;
import com.threethan.questpatcher.activities.APKInstallerActivity;
import com.threethan.questpatcher.activities.InstallerFilePickerActivity;
import com.threethan.questpatcher.adapters.APKsAdapter;
import com.threethan.questpatcher.utils.APKData;
import com.threethan.questpatcher.utils.APKEditorUtils;
import com.threethan.questpatcher.utils.APKExplorer;
import com.threethan.questpatcher.utils.AppData;
import com.threethan.questpatcher.utils.Common;
import com.threethan.questpatcher.utils.tasks.ExploreAPK;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.tabs.TabLayout;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import in.sunilpaulmathew.sCommon.CommonUtils.sCommonUtils;
import in.sunilpaulmathew.sCommon.CommonUtils.sExecutor;
import in.sunilpaulmathew.sCommon.FileUtils.sFileUtils;

Context:
app/src/main/java/com/threethan/questpatcher/fragments/APKsFragment.java
package com.threethan.questpatcher.fragments;

/*
 * Created by APK Explorer & Editor <apkeditor@protonmail.com> on March 04, 2021
 */
public class APKsFragment extends Fragment {

    private LinearLayoutCompat mProgress;
    private RecyclerView mRecyclerView;
    private APKsAdapter mRecycleViewAdapter;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View mRootView = inflater.inflate(R.layout.fragment_apks, container, false);

        Common.initializeAPKsTitle(mRootView, R.id.app_title);
        Common.initializeAPKsSearchWord(mRootView, R.id.search_word);
        mProgress = mRootView.findViewById(R.id.progress_layout);
        AppCompatImageButton mSearchButton = mRootView.findViewById(R.id.search_button);
        AppCompatImageButton mSortButton = mRootView.findViewById(R.id.sort_button);
        AppCompatImageButton mAddButton = mRootView.findViewById(R.id.add_button);
        LinearLayoutCompat mBottomLayout = mRootView.findViewById(R.id.layout_bottom);
        TabLayout mTabLayout = mRootView.findViewById(R.id.tab_layout);
        mRecyclerView = mRootView.findViewById(R.id.recycler_view);

        mRecyclerView.setLayoutManager(new LinearLayoutManager(requireActivity()));

        Common.getAPKsTitle().setText(getString(R.string.apps_exported));
        mTabLayout.setVisibility(View.VISIBLE);

        mTabLayout.addTab(mTabLayout.newTab().setText(getString(R.string.apks)));
        mTabLayout.addTab(mTabLayout.newTab().setText(getString(R.string.bundles)));

        Objects.requireNonNull(mTabLayout.getTabAt(getTabPosition(requireActivity()))).select();

        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                String mStatus = sCommonUtils.getString("apkTypes", "apks", requireActivity());
                switch (tab.getPosition()) {
                    case 0:
                        if (!mStatus.equals("apks")) {
                            sCommonUtils.saveString("apkTypes", "apks", requireActivity());
                            loadAPKs(requireActivity());
                        }
                        break;
                    case 1:
                        if (!mStatus.equals("bundles")) {
                            sCommonUtils.saveString("apkTypes", "bundles", requireActivity());
                            loadAPKs(requireActivity());
                        }
                        break;
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });

        mSearchButton.setOnClickListener(v -> {
            if (Common.getAPKsSearchWord().getVisibility() == View.VISIBLE) {
                Common.getAPKsSearchWord().setVisibility(View.GONE);
                Common.getAPKsTitle().setVisibility(View.VISIBLE);
                if (Common.getAPKsSearchWord() != null) {
                    Common.getAPKsSearchWord().setText(null);
                }
                AppData.toggleKeyboard(0, Common.getAPKsSearchWord(), requireActivity());
            } else {
                Common.getAPKsSearchWord().setVisibility(View.VISIBLE);
                Common.getAPKsSearchWord().requestFocus();
                Common.getAPKsTitle().setVisibility(View.GONE);
                AppData.toggleKeyboard(1, Common.getAPKsSearchWord(), requireActivity());
            }
        });

app/src/main/java/com/threethan/questpatcher/utils/Common.java
public class Common {

    private static AppCompatEditText mSearchWordApks, mSearchWordApps, mSearchWordProjects;
    private static boolean mBuilding = false, mBusy = false, mCancel = false, mFinish = false,
            mPrivateKey = false, mReloading = false, mRSATemplate = false;
    private static List<File> mFile = null;
    private static List<PackageItems> mPackageData = null;
    private static final List<String> mAPKList = new ArrayList<>(), mErrorList = new ArrayList<>();
    private static int mError = 0, mSuccess = 0;
    private static MaterialCardView mSelect;
    private static MaterialTextView mApksTitle, mAppsTitle, mProjectsTitle;
    private static String mAppID, mFilePath = null, mFileToReplace = null, mPackageName = null,
            mPath = null, mSearchWord, mStatus = null;

    public static AppCompatEditText getAPKsSearchWord() {
        return mSearchWordApks;
    }

    public static AppCompatEditText getAppsSearchWord() {
        return mSearchWordApps;
    }

    public static AppCompatEditText getProjectsSearchWord() {
        return mSearchWordProjects;
    }

    public static boolean isBuilding() {
        return mBuilding;
    }

    public static boolean isBusy() {
        return mBusy;
    }

    public static boolean isCancelled() {
        return mCancel;
    }

    public static boolean isFinished() {
        return mFinish;
    }

    public static boolean isReloading() {
        return mReloading;
    }

    public static boolean isTextMatched(String searchText, String searchWord) {
        for (int a = 0; a < searchText.length() - searchWord.length() + 1; a++) {
            if (searchWord.equalsIgnoreCase(searchText.substring(a, a + searchWord.length()))) {
                return true;
            }
        }
        return false;
    }

    public static boolean hasPrivateKey() {
        return mPrivateKey;
    }

    public static boolean hasRASATemplate() {
        return mRSATemplate;
    }

    public static int getError() {
        return mError;
    }

    public static int getSuccess() {
        return mSuccess;
    }

    public static List<File> getFiles() {
        return mFile;
    }

    public static List<PackageItems> getPackageData() {
        return mPackageData;
    }

    public static List<String> getAPKList() {
        return mAPKList;
    }

    public static List<String> getErrorList() {
        return mErrorList;
    }

    public static MaterialCardView getSelectCard() {
        return mSelect;
    }

    public static MaterialTextView getAPKsTitle() {
        return mApksTitle;
    }

    public static MaterialTextView getAppsTitle() {
        return mAppsTitle;
    }

    public static MaterialTextView getProjectsTitle() {
        return mProjectsTitle;
    }

    public static String getAppID() {
        return mAppID;
    }

    public static String getFilePath() {
        return mFilePath;
    }

    public static String getFileToReplace() {
        return mFileToReplace;
    }

    public static String getPackageName() {
        return mPackageName;
    }

    public static String getPath() {
        return mPath;
    }

    public static String getSearchWord() {
        return mSearchWord;
    }

    public static String getStatus() {
        return mStatus;
    }

    public static void addToFilesList(File file) {
        if (mFile == null) {
            mFile = new ArrayList<>();
        }
        mFile.add(file);
    }

    public static void clearFilesList() {
        mFile = null;
    }

    public static void initializeAPKsSearchWord(View view, int id) {
        mSearchWordApks = view.findViewById(id);
    }

    public static void initializeAPKsTitle(View view, int id) {
        mApksTitle = view.findViewById(id);
    }

    public static void initializeAppsSearchWord(View view, int id) {
        mSearchWordApps = view.findViewById(id);
    }

    public static void initializeAppsTitle(View view, int id) {
        mAppsTitle = view.findViewById(id);
    }

    public static void initializeProjectsSearchWord(View view, int id) {
        mSearchWordProjects = view.findViewById(id);
    }

    public static void initializeProjectsTitle(View view, int id) {
        mProjectsTitle = view.findViewById(id);
    }

    public static void initializeView(View view, int id) {
        mSelect = view.findViewById(id);
    }

    public static void isBuilding(boolean b) {
        mBuilding = b;
    }

    public static void isCancelled(boolean b) {
        mCancel = b;
    }

    public static void isReloading(boolean b) {
        mReloading = b;
    }

    public static void removeFromFilesList(File file) {
        if (mFile == null || mFile.size() == 0) return;
        mFile.remove(file);
    }

    public static void setFinishStatus(boolean b) {
        mFinish = b;
    }

    public static void setPrivateKeyStatus(boolean b) {
        mPrivateKey = b;
    }

    public static void setRSATemplateStatus(boolean b) {
        mRSATemplate = b;
    }

    public static void setAppID(String appID) {
        mAppID = appID;
    }

    public static void setError(int i) {
        mError = i;
    }

    public static void setFilePath(String filePath) {
        mFilePath = filePath;
    }

    public static void setFileToReplace(String fileToReplace) {
        mFileToReplace = fileToReplace;
    }

    public static void setPackageName(String packageName) {
        mPackageName = packageName;
    }

    public static void setPackageData(List<PackageItems> data) {
        mPackageData = data;
    }

    public static void setPath(String path) {
        mPath = path;
    }

    public static void setProgress(boolean b, View view) {
        mBusy = b;
        view.setVisibility(b ? View.VISIBLE : View.GONE);
    }

    public static void setSearchWord(String searchWord) {
        mSearchWord = searchWord;
    }

    public static void setStatus(String status) {
        mStatus = status;
    }

    public static void setSuccess(int i) {
        mSuccess = i;
    }

}

app/src/main/java/com/threethan/questpatcher/activities/APKInstallerActivity.java
public class APKInstallerActivity extends AppCompatActivity {

    private AppCompatImageButton mExploreIcon;
    private AppCompatImageView mAppIcon;
    private APKParser mAPKParser;
    private File mFile = null;
    private LinearLayoutCompat mMainLayout, mIconsLayout;
    private MaterialCardView mCancel, mInstall;
    private MaterialTextView mAppName, mInstallText, mPackageID;
    private TabLayout mTabLayout;
    private ViewPager mViewPager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_apkdetails);

        mExploreIcon = findViewById(R.id.explore);
        mAppIcon = findViewById(R.id.app_image);
        mAppName = findViewById(R.id.app_title);
        mPackageID = findViewById(R.id.package_id);
        mMainLayout = findViewById(R.id.main_layout);
        mIconsLayout = findViewById(R.id.icons_layout);
        mInstall = findViewById(R.id.install);
        mInstallText = findViewById(R.id.install_text);
        mCancel = findViewById(R.id.cancel);
        mTabLayout = findViewById(R.id.tab_Layout);
        mViewPager = findViewById(R.id.view_pager);

        Bundle bundle = getIntent().getExtras();
        if (bundle != null && bundle.containsKey("apkFileUri") && bundle.getString("apkFileUri") != null) {
            manageInstallation(Uri.parse(bundle.getString("apkFileUri")), null, this).execute();
        } else if (bundle != null && bundle.containsKey("apkFilePath") && bundle.getString("apkFilePath") != null) {
            manageInstallation(null, bundle.getString("apkFilePath"), this).execute();
        } else if (getIntent().getData() != null) {
            manageInstallation(getIntent().getData(), null, this).execute();
        }
    }

    private sExecutor manageInstallation(Uri uri, String filePath, Activity activity) {
        return new sExecutor() {
            private ProgressDialog mProgressDialog;

            @Override
            public void onPreExecute() {
                mProgressDialog = new ProgressDialog(activity);
                mProgressDialog.setMessage(activity.getString(R.string.loading));
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setIcon(R.mipmap.ic_launcher);
                mProgressDialog.setTitle(R.string.app_name);
                mProgressDialog.setIndeterminate(true);
                mProgressDialog.setCancelable(false);
                mProgressDialog.show();

                sFileUtils.delete(getExternalFilesDir("APK"));
                if (filePath == null) {
                    String fileName = Objects.requireNonNull(DocumentFile.fromSingleUri(activity, uri)).getName();
                    mFile = new File(getExternalFilesDir("APK"), Objects.requireNonNull(fileName));
                }
                Common.getAPKList().clear();
            }

            @Override
            public void doInBackground() {
                if (filePath != null) {
                    mFile = new File(filePath);
                } else {
                    sFileUtils.copy(uri, mFile, activity);
                }
                try {
                    mAPKParser = new APKParser();
                    mAPKParser.parse(mFile.getAbsolutePath(), activity);
                } catch (Exception ignored) {
                }
            }

            @Override
            public void onPostExecute() {
                try {
                    mProgressDialog.dismiss();
                } catch (IllegalArgumentException ignored) {
                }
                if (mFile.exists()) {
                    if (mAPKParser.isParsed()) {
                        loadAPKDetails(activity);
                        if (sPackageUtils.isPackageInstalled(mAPKParser.getPackageName(), activity)) {
                            mInstallText.setText(getString(R.string.update));
                        }
                    } else if (mFile.getName().endsWith("apkm") || mFile.getName().endsWith("apks") || mFile.getName().endsWith("xapk")) {
                        new SelectBundleDialog(mFile.getAbsolutePath(), true, activity).show();
                    } else {
                        new InvalidFileDialog(true, activity).show();
                    }
                } else {
                    new MaterialAlertDialogBuilder(activity)
                            .setIcon(R.mipmap.ic_launcher)
                            .setTitle(R.string.split_apk_installer)
                            .setMessage(getString(R.string.file_path_error))
                            .setCancelable(false)
                            .setPositiveButton(R.string.cancel, (dialogInterface, i) -> finish()).show();
                }
            }
        };
    }

    private void loadAPKDetails(Activity activity) {
        sPagerAdapter adapter = new sPagerAdapter(getSupportFragmentManager());
        try {
            if (sPackageUtils.isPackageInstalled(mAPKParser.getPackageName(), activity)) {
                mAppName.setText(sPackageUtils.getAppName(mAPKParser.getPackageName(), activity));
                mPackageID.setText(mAPKParser.getPackageName());
                mAppIcon.setImageDrawable(sPackageUtils.getAppIcon(mAPKParser.getPackageName(), activity));
                mPackageID.setVisibility(View.VISIBLE);
            } else {
                mAppName.setText(mAPKParser.getPackageName());
                mAppIcon.setImageDrawable(mAPKParser.getAppIcon());
            }

            adapter.AddFragment(new APKDetailsFragment(), getString(R.string.details));
            if (mAPKParser.getPermissions() != null) {
                adapter.AddFragment(new PermissionsFragment(), getString(R.string.permissions));
            }
            if (mAPKParser.getManifest() != null) {
                adapter.AddFragment(new ManifestFragment(), getString(R.string.manifest));
            }
            if (mAPKParser.getCertificate() != null) {
                adapter.AddFragment(new CertificateFragment(), getString(R.string.certificate));
            }
        } catch (Exception ignored) {}

        mViewPager.setAdapter(adapter);
        mTabLayout.setupWithViewPager(mViewPager);
        mMainLayout.setVisibility(View.VISIBLE);
        mIconsLayout.setVisibility(View.VISIBLE);

        mCancel.setOnClickListener(v -> finish());
        mInstall.setOnClickListener(v -> {
            Common.getAPKList().add(mFile.getAbsolutePath());
            APKExplorer.handleAPKs(true, activity);
        });

        mExploreIcon.setOnClickListener(v -> {
            new ExploreAPK(null, mFile, null, activity).execute();
            activity.finish();
        });
    }

    @Override
    public void onBackPressed() {
        finish();
    }

}

app/src/main/java/com/threethan/questpatcher/utils/APKExplorer.java
public class APKExplorer {

    public static List<String> getData(File[] files, boolean supported, Activity activity) {
        List<String> mData = new ArrayList<>(), mDir = new ArrayList<>(), mFiles = new ArrayList<>();
        try {
            // Add directories
            for (File mFile : files) {
                if (mFile.isDirectory() && !mFile.getName().matches(".aeeBackup|.aeeBuild")) {
                    mDir.add(mFile.getAbsolutePath());
                }
            }
            Collections.sort(mDir, String.CASE_INSENSITIVE_ORDER);
            if (!sCommonUtils.getBoolean("az_order", true, activity)) {
                Collections.reverse(mDir);
            }
            mData.addAll(mDir);
            // Add files
            for (File mFile :files) {
                if (supported) {
                    if (mFile.isFile()) {
                        mFiles.add(mFile.getAbsolutePath());
                    }
                } else if (mFile.isFile() && isSupportedFile(mFile.getAbsolutePath())) {
                    mFiles.add(mFile.getAbsolutePath());

                }
            }
            Collections.sort(mFiles, String.CASE_INSENSITIVE_ORDER);
            if (!sCommonUtils.getBoolean("az_order", true, activity)) {
                Collections.reverse(mFiles);
            }
            mData.addAll(mFiles);
        } catch (NullPointerException ignored) {
            activity.finish();
        }
        return mData;
    }

    public static boolean isTextFile(String path) {
        return path.endsWith(".txt") || path.endsWith(".xml") || path.endsWith(".json") || path.endsWith(".properties")
                || path.endsWith(".version") || path.endsWith(".sh") || path.endsWith(".MF") || path.endsWith(".SF")
                || path.endsWith(".html") || path.endsWith(".ini") || path.endsWith(".smali");
    }

    public static boolean isImageFile(String path) {
        return path.endsWith(".bmp") || path.endsWith(".png") || path.endsWith(".jpg");
    }

    public static boolean isBinaryXML(String path) {
        return path.endsWith(".xml") && (new File(path).getName().equals("AndroidManifest.xml") || path.contains(Common.getAppID() + "/res/"));
    }

    public static boolean isSmaliEdited(String path) {
        if (getAppData(path) == null) return false;
        try {
            return Objects.requireNonNull(getAppData(path)).getBoolean("smali_edited");
        } catch (JSONException ignored) {
        }
        return false;
    }

    public static Bitmap getAppIcon(String path) {
        if (getAppData(path) == null) return null;
        try {
            return stringToBitmap(Objects.requireNonNull(getAppData(path)).getString("app_icon"));
        } catch (JSONException ignored) {
        }
        return null;
    }

    public static Bitmap stringToBitmap(String string) {
        try {
            byte[] imageAsBytes = Base64.decode(string.getBytes(), Base64.DEFAULT);
            return BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
        } catch (Exception ignored) {}
        return null;
    }

    private static boolean isSupportedFile(String path) {
        return path.endsWith(".apk") || path.endsWith(".apks") || path.endsWith(".apkm") || path.endsWith(".xapk");
    }

    public static JSONObject getAppData(String path) {
        if (sFileUtils.read(new File(path)) == null) return null;
        try {
            return new JSONObject(sFileUtils.read(new File(path)));
        } catch (JSONException ignored) {
        }
        return null;
    }

    public static void setIcon(AppCompatImageButton icon, Drawable drawable, Context context) {
        icon.setImageDrawable(drawable);
        icon.setColorFilter(sThemeUtils.isDarkTheme(context) ? ContextCompat.getColor(context, R.color.colorWhite) :
                ContextCompat.getColor(context, R.color.colorBlack));
    }

    public static int getSpanCount(Activity activity) {
        return sCommonUtils.getOrientation(activity) == Configuration.ORIENTATION_LANDSCAPE ? 2 : 1;
    }

    public static String getAppName(String path) {
        if (getAppData(path) == null) return null;
        try {
            return Objects.requireNonNull(getAppData(path)).getString("app_name");
        } catch (JSONException ignored) {
        }
        return null;
    }

    public static String getPackageName(String path) {
        if (getAppData(path) == null) return null;
        try {
            return Objects.requireNonNull(getAppData(path)).getString("package_name");
        } catch (JSONException ignored) {
        }
        return null;
    }

    public static List<String> getTextViewData(String path, String searchWord, boolean parsedManifest, Context context) {
        List<String> mData = new ArrayList<>();
        String text = null;
        if (isBinaryXML(path)) {
            try (FileInputStream inputStream = new FileInputStream(path)) {
                text = new aXMLDecoder().decode(inputStream).trim();
            } catch (Exception e) {
                sCommonUtils.toast(context.getString(R.string.xml_decode_failed, new File(path).getName()), context).show();
            }
        } else if (parsedManifest) {
            text = path;
        } else {
            text = sFileUtils.read(new File(path));
        }
        if (text != null) {
            for (String line : text.split("\\r?\\n")) {
                if (searchWord == null) {
                    mData.add(line);
                } else if (Common.isTextMatched(line, searchWord)) {
                    mData.add(line);
                }
            }
        }
        return mData;
    }

    public static Uri getIconFromPath(String path) {
        File mFile = new File(path);
        if (mFile.exists()) {
            return Uri.fromFile(mFile);
        }
        return null;
    }

    public static void saveImage(Bitmap bitmap, String dest, Context context) {
        try {
            OutputStream imageOutStream;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.MediaColumns.DISPLAY_NAME, new File(dest).getName());
                values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
                values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
                Uri uri = context.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values);
                imageOutStream = context.getContentResolver().openOutputStream(uri);
            } else {
                File image = new File(dest);
                imageOutStream = new FileOutputStream(image);
            }
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, imageOutStream);
            imageOutStream.close();
        } catch(Exception ignored) {
        }
    }

    public static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap;
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            if(bitmapDrawable.getBitmap() != null) {
                return bitmapDrawable.getBitmap();
            }
        }
        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
        } else {
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        }
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    private static void installAPKs(boolean exit, Activity activity) {
        SplitAPKInstaller.installSplitAPKs(exit, Common.getAPKList(), null, activity);
    }

    public static void handleAPKs(boolean exit, Activity activity) {
        if (APKEditorUtils.isFullVersion(activity)) {
            if (sCommonUtils.getString("installerAction", null, activity) == null) {
                new sSingleItemDialog(0, null, new String[] {
                        activity.getString(R.string.install),
                        activity.getString(R.string.install_resign),
                        activity.getString(R.string.resign_only)
                }, activity) {

                    @Override
                    public void onItemSelected(int itemPosition) {
                        sCommonUtils.saveBoolean("firstSigning", true, activity);
                        if (itemPosition == 0) {
                            installAPKs(exit, activity);
                        } else if (itemPosition == 1) {
                            if (!sCommonUtils.getBoolean("firstSigning", false, activity)) {
                                new SigningOptionsDialog(null, exit, activity).show();
                            } else {
                                new ResignAPKs(null, true, exit, activity).execute();
                            }
                        } else {
                            if (!sCommonUtils.getBoolean("firstSigning", false, activity)) {
                                new SigningOptionsDialog(null, exit, activity).show();
                            } else {
                                new ResignAPKs(null, false, exit, activity).execute();
                            }
                        }
                    }
                }.show();
            } else if (sCommonUtils.getString("installerAction", null, activity).equals(activity.getString(R.string.install))) {
                installAPKs(exit, activity);
            } else {
                if (!sCommonUtils.getBoolean("firstSigning", false, activity)) {
                    new SigningOptionsDialog(null, exit, activity).show();
                } else {
                    new ResignAPKs(null,true, exit, activity).execute();
                }
            }
        } else {
            installAPKs(exit, activity);
        }
    }

}

app/src/main/java/com/threethan/questpatcher/utils/AppData.java
public class AppData {

    public static List<PackageItems> getRawData(ProgressBar progressBar, Context context) {
        List<PackageItems> mData = new ArrayList<>();
        List<ApplicationInfo> packages = context.getPackageManager().getInstalledApplications(0);
        for (ApplicationInfo packageInfo: packages) {
            progressBar.setMax(packages.size());
            try {
                PackageItems pi = new PackageItems(
                        packageInfo.packageName,
                        context);
                // If PackageItems construction survived, then add
                mData.add(pi);
            } catch (Exception ignored) {
            }
            if (progressBar.getProgress() < packages.size()) {
                progressBar.setProgress(progressBar.getProgress() + 1);
            }
        }
        return mData;
    }

    public static List<PackageItems> getData(Context context) {
        List<PackageItems> mData = new ArrayList<>();
        try {
            boolean mAppType;
            for (PackageItems packageItem : Common.getPackageData()) {
                if (sCommonUtils.getString("appTypes", "all", context).equals("system")) {
                    mAppType = sPackageUtils.isSystemApp(packageItem.getPackageName(), context);
                } else if (sCommonUtils.getString("appTypes", "all", context).equals("user")) {
                    mAppType = !sPackageUtils.isSystemApp(packageItem.getPackageName(), context);
                } else {
                    mAppType = true;
                }
                if (mAppType) {
                    if (Common.getSearchWord() == null) {
                        mData.add(packageItem);
                    } else if (Common.isTextMatched(packageItem.getAppName(), Common.getSearchWord())
                            || Common.isTextMatched(packageItem.getPackageName(), Common.getSearchWord())) {
                        mData.add(packageItem);
                    }
                }
            }
            if (sCommonUtils.getBoolean("sort_name", false, context)) {
                Collections.sort(mData, (lhs, rhs) -> String.CASE_INSENSITIVE_ORDER.compare(lhs.getAppName(), rhs.getAppName()));
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && sCommonUtils.getBoolean("sort_size", false, context)) {
                Collections.sort(mData, Comparator.comparingLong(PackageItems::getAPKSize));
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && sCommonUtils.getBoolean("sort_installed", false, context)) {
                Collections.sort(mData, Comparator.comparingLong(PackageItems::getInstalledTime));
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && sCommonUtils.getBoolean("sort_updated", false, context)) {
                Collections.sort(mData, Comparator.comparingLong(PackageItems::getUpdatedTime));
            } else {
                Collections.sort(mData, (lhs, rhs) -> String.CASE_INSENSITIVE_ORDER.compare(lhs.getPackageName(), rhs.getPackageName()));
            }
            if (!sCommonUtils.getBoolean("az_order", true, context)) {
                Collections.reverse(mData);
            }
        } catch (NullPointerException ignored) {}
        return mData;
    }

    public static PackageInfo getPackageInfo(String packageName, Context context) {
        try {
            return context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
        } catch (Exception ignored) {
        }
        return null;
    }

    /*
     * Based on the work of https://github.com/ZenerDeveloper
     * Ref: https://github.com/SmartPack/PackageManager/commit/1ac499d0ed8922c02875df029ead80a17f1c40e1
     */
    public static void toggleKeyboard(int mode, AppCompatEditText textView, Context context) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (mode == 1) {
            if (textView.requestFocus()) {
                imm.showSoftInput(textView, InputMethodManager.SHOW_IMPLICIT);
            }
        } else {
            imm.hideSoftInputFromWindow(textView.getWindowToken(), 0);
        }
    }

}

app/src/main/java/com/threethan/questpatcher/utils/APKEditorUtils.java
public class APKEditorUtils {

    public static int getThemeAccentColor(Context context) {
        TypedValue value = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.colorAccent, value, true);
        return value.data;
    }

    public static boolean isFullVersion(Context context) {
        return true;
    }

    public static CharSequence fromHtml(String text) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY);
        } else {
            return Html.fromHtml(text);
        }
    }

    public static void unzip(String zip, String path) {
        try (ZipFile zipFile = new ZipFile(zip)) {
            zipFile.extractAll(path);
        } catch (IOException ignored) {
        }
    }

    public static void zip(File path, File zip) {
        try (ZipFile zipFile = new ZipFile(zip)) {
            for (File mFile : Objects.requireNonNull(path.listFiles())) {
                if (mFile.isDirectory()) {
                    ZipParameters zipParameters = new ZipParameters();
                    zipParameters.setCompressionMethod(CompressionMethod.STORE);
                    zipFile.addFolder(mFile, zipParameters);
                } else {
                    ZipParameters zipParameters = new ZipParameters();
                    zipParameters.setCompressionMethod(CompressionMethod.STORE);
                    zipFile.addFile(mFile, zipParameters);
                }
            }
        } catch (IOException ignored) {
        }
    }

    public static boolean isDocumentsUI(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

}

app/src/main/java/com/threethan/questpatcher/adapters/APKsAdapter.java
public class APKsAdapter extends RecyclerView.Adapter<APKsAdapter.ViewHolder> {

    private static List<String> data;

    public APKsAdapter(List<String> data) {
        APKsAdapter.data = data;
    }

    @NonNull
    @Override
    public APKsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View rowItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_view_apks, parent, false);
        return new ViewHolder(rowItem);
    }

    @SuppressLint({"NotifyDataSetChanged", "StringFormatInvalid"})
    @Override
    public void onBindViewHolder(@NonNull APKsAdapter.ViewHolder holder, int position) {
        try {
            if (new File(data.get(position)).isDirectory()) {
                if (sAPKUtils.getAPKIcon(data.get(position) + "/base.apk", holder.mAppName.getContext()) != null) {
                    holder.mAppIcon.setImageDrawable(sAPKUtils.getAPKIcon(data.get(position) + "/base.apk", holder.mAppName.getContext()));
                } else {
                    holder.mAppIcon.setImageDrawable(ContextCompat.getDrawable(holder.mAppIcon.getContext(), R.drawable.ic_android));
                    holder.mAppIcon.setColorFilter(APKEditorUtils.getThemeAccentColor(holder.mAppIcon.getContext()));
                }
                if (Common.getSearchWord() != null && Common.isTextMatched(new File(data.get(position)).getName(), Common.getSearchWord())) {
                    holder.mAppName.setText(APKEditorUtils.fromHtml(new File(data.get(position)).getName().replace(Common.getSearchWord(),
                            "<b><i><font color=\"" + Color.RED + "\">" + Common.getSearchWord() + "</font></i></b>")));
                } else {
                    holder.mAppName.setText(new File(data.get(position)).getName());
                }
                if (sAPKUtils.getPackageName(data.get(position) + "/base.apk", holder.mAppName.getContext()) == null) {
                    holder.mAppName.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG);
                    holder.mCard.setOnClickListener(v -> sCommonUtils.snackBar(v, v.getContext().getString(R.string.apk_corrupted)).show());
                }
                if (sAPKUtils.getVersionName(data.get(position) + "/base.apk", holder.mAppName.getContext()) != null) {
                    holder.mVersion.setText(holder.mVersion.getContext().getString(R.string.version, sAPKUtils.getVersionName(data.get(position) + "/base.apk", holder.mAppName.getContext())));
                }
                holder.mCard.setOnClickListener(v -> {
                    if (APKEditorUtils.isFullVersion(v.getContext())) {
                        if (data.get(position).contains("_aee-signed") && !sCommonUtils.getBoolean("signature_warning", false, v.getContext())) {
                            new SignatureMismatchDialog(v.getContext()).show();
                        } else {
                            new MaterialAlertDialogBuilder(v.getContext())
                                    .setIcon(R.mipmap.ic_launcher)
                                    .setTitle(R.string.app_name)
                                    .setMessage(v.getContext().getString(R.string.install_question, new File(data.get(position)).getName()))
                                    .setNegativeButton(R.string.cancel, (dialog, id) -> {
                                    })
                                    .setPositiveButton(R.string.install, (dialog, id) -> SplitAPKInstaller.installSplitAPKs(false, null,
                                            data.get(position) + "/base.apk", (Activity) v.getContext())
                                    ).show();
                        }
                    } else {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            new BundleOptionsMenu(data.get(position), v);
                        } else {
                            new ShareBundleDialog(data.get(position), holder.mCard.getContext()).show();
                        }
                    }
                });
                holder.mCard.setOnLongClickListener(v -> {
                    if (APKEditorUtils.isFullVersion(v.getContext())) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            new BundleOptionsMenu(data.get(position), v);
                        } else {
                            new ShareBundleDialog(data.get(position), holder.mCard.getContext()).show();
                        }
                    }
                    return false;
                });
            } else {
                if (sAPKUtils.getAPKIcon(data.get(position), holder.mAppName.getContext()) != null) {
                    holder.mAppIcon.setImageDrawable(sAPKUtils.getAPKIcon(data.get(position), holder.mAppName.getContext()));
                } else {
                    holder.mAppIcon.setImageDrawable(ContextCompat.getDrawable(holder.mAppIcon.getContext(), R.drawable.ic_android));
                    holder.mAppIcon.setColorFilter(APKEditorUtils.getThemeAccentColor(holder.mAppIcon.getContext()));
                }
                if (sAPKUtils.getAPKName(data.get(position), holder.mAppName.getContext()) != null) {
                    if (Common.getSearchWord() != null && Common.isTextMatched(Objects.requireNonNull(sAPKUtils.getAPKName(data.get(position), holder.mAppName.getContext())).toString(), Common.getSearchWord())) {
                        holder.mAppName.setText(APKEditorUtils.fromHtml(Objects.requireNonNull(sAPKUtils.getAPKName(data.get(position), holder.mAppName.getContext())).toString().replace(Common.getSearchWord(),
                                "<b><i><font color=\"" + Color.RED + "\">" + Common.getSearchWord() + "</font></i></b>")));
                    } else {
                        holder.mAppName.setText(sAPKUtils.getAPKName(data.get(position), holder.mAppName.getContext()));
                    }
                } else {
                    if (Common.getSearchWord() != null && Common.isTextMatched(new File(data.get(position)).getName(), Common.getSearchWord())) {
                        holder.mAppName.setText(APKEditorUtils.fromHtml(new File(data.get(position)).getName().replace(Common.getSearchWord(),
                                "<b><i><font color=\"" + Color.RED + "\">" + Common.getSearchWord() + "</font></i></b>")));
                    } else {
                        holder.mAppName.setText(new File(data.get(position)).getName());
                    }
                    holder.mAppName.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG);
                    holder.mCard.setOnClickListener(v -> sCommonUtils.snackBar(v, v.getContext().getString(R.string.apk_corrupted)).show());
                }
                if (sAPKUtils.getVersionName(data.get(position), holder.mAppName.getContext()) != null) {
                    holder.mVersion.setText(holder.mVersion.getContext().getString(R.string.version, sAPKUtils.getVersionName(data.get(position), holder.mAppName.getContext())));
                }
                holder.mSize.setText(holder.mSize.getContext().getString(R.string.size, sAPKUtils.getAPKSize(new File(data.get(position)).length())));
                holder.mSize.setTextColor(sThemeUtils.isDarkTheme(holder.mSize.getContext()) ? Color.GREEN : Color.BLACK);
                holder.mSize.setVisibility(View.VISIBLE);
                holder.mCard.setOnClickListener(v -> {
                    if (APKEditorUtils.isFullVersion(v.getContext())) {
                        if (data.get(position).contains("_aee-signed.apk") && !sCommonUtils.getBoolean("signature_warning", false, v.getContext())) {
                            new SignatureMismatchDialog(v.getContext()).show();
                        } else {
                            new MaterialAlertDialogBuilder(v.getContext())
                                    .setIcon(R.mipmap.ic_launcher)
                                    .setTitle(R.string.app_name)
                                    .setMessage(v.getContext().getString(R.string.install_question, new File(data.get(position)).getName()))
                                    .setNegativeButton(R.string.cancel, (dialog, id) -> {
                                    })
                                    .setPositiveButton(R.string.install, (dialog, id) -> SplitAPKInstaller.installAPK(false, new File(data.get(position)), (Activity) v.getContext())).show();
                        }
                    } else {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            new APKOptionsMenu(new File(data.get(position)), v);
                        } else {
                            APKData.shareFile(new File(data.get(position)), "application/java-archive", v.getContext());
                        }
                    }
                });
                holder.mCard.setOnLongClickListener(v -> {
                    if (APKEditorUtils.isFullVersion(v.getContext())) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            new APKOptionsMenu(new File(data.get(position)), v);
                        } else {
                            APKData.shareFile(new File(data.get(position)), "application/java-archive", v.getContext());
                        }
                    }
                    return false;
                });
            }
            holder.mCard.setCardBackgroundColor(sThemeUtils.isDarkTheme(holder.mCard.getContext()) ? Color.DKGRAY : Color.LTGRAY);
            holder.mCard.setStrokeColor(sThemeUtils.isDarkTheme(holder.mCard.getContext()) ? Color.DKGRAY : Color.LTGRAY);
            holder.mVersion.setVisibility(View.VISIBLE);
        } catch (NullPointerException ignored) {
        }
        holder.mDelete.setOnClickListener(v -> new MaterialAlertDialogBuilder(v.getContext())
                .setIcon(R.mipmap.ic_launcher)
                .setTitle(R.string.app_name)
                .setMessage(v.getContext().getString(R.string.delete_question, new File(data.get(position)).getName()))
                .setNegativeButton(R.string.cancel, (dialog, id) -> {
                })
                .setPositiveButton(R.string.delete, (dialog, id) -> {
                    sFileUtils.delete(new File(data.get(position)));
                    data.remove(position);
                    notifyItemRemoved(position);
                    notifyDataSetChanged();
                }).show());
        holder.mDelete.setColorFilter(Color.RED);
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final AppCompatImageButton mAppIcon, mDelete;
        private final MaterialCardView mCard;
        private final MaterialTextView mAppName, mSize, mVersion;

        public ViewHolder(View view) {
            super(view);
            this.mCard = view.findViewById(R.id.card);
            this.mAppIcon = view.findViewById(R.id.icon);
            this.mDelete = view.findViewById(R.id.delete);
            this.mAppName = view.findViewById(R.id.title);
            this.mSize = view.findViewById(R.id.size);
            this.mVersion = view.findViewById(R.id.version);
        }
    }

}

app/src/main/java/com/threethan/questpatcher/activities/InstallerFilePickerActivity.java
public class InstallerFilePickerActivity extends AppCompatActivity {

    private LinearLayoutCompat mProgressLayout;
    private InstallerFilePickerAdapter mRecycleViewAdapter;
    private MaterialTextView mTitle;
    private RecyclerView mRecyclerView;
    public static final String TITLE_INTENT = "title";

    @SuppressLint("StringFormatInvalid")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_installerfilepicker);

        AppCompatImageButton mBack = findViewById(R.id.back);
        mTitle = findViewById(R.id.title);
        AppCompatImageButton mSortButton = findViewById(R.id.sort);
        Common.initializeView(findViewById(android.R.id.content), R.id.select);
        mProgressLayout = findViewById(R.id.progress_layout);
        mRecyclerView = findViewById(R.id.recycler_view);

        mBack.setOnClickListener(v -> super.onBackPressed());

        if (Build.VERSION.SDK_INT < 29 && sPermissionUtils.isPermissionDenied(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,this)) {
            LinearLayoutCompat mPermissionLayout = findViewById(R.id.permission_layout);
            View mPermissionGrant = findViewById(R.id.grant_card);
            mPermissionLayout.setVisibility(View.VISIBLE);
            mRecyclerView.setVisibility(View.GONE);
            mPermissionGrant.setOnClickListener(v -> sPermissionUtils.requestPermission(
                    new String[] {
                            android.Manifest.permission.WRITE_EXTERNAL_STORAGE
                    },this));
            return;
        }

        mRecyclerView.setLayoutManager(new GridLayoutManager(this, APKExplorer.getSpanCount(this)));
        mRecycleViewAdapter = new InstallerFilePickerAdapter(APKExplorer.getData(getFilesList(), false, this));
        mRecyclerView.setAdapter(mRecycleViewAdapter);

        if (getIntent().getStringExtra(TITLE_INTENT) != null) {
            mTitle.setText(getIntent().getStringExtra(TITLE_INTENT));
        } else {
            mTitle.setText(Common.getPath().equals(Environment.getExternalStorageDirectory().toString() + File.separator) ? getString(R.string.sdcard) : new File(Common.getPath()).getName());
        }

        mRecycleViewAdapter.setOnItemClickListener((position, v) -> {
            if (new File(APKExplorer.getData(getFilesList(), false, this).get(position)).isDirectory()) {
                Common.setPath(APKExplorer.getData(getFilesList(), false, this).get(position));
                reload(this);
            } else if (APKExplorer.getData(getFilesList(), false, this).get(position).endsWith(".apks") || APKExplorer.getData(getFilesList(), false,
                    this).get(position).endsWith(".apkm") || APKExplorer.getData(getFilesList(), false, this).get(position).endsWith(".xapk")) {
                new MaterialAlertDialogBuilder(this)
                        .setMessage(getString(R.string.bundle_install_question, new File(APKExplorer.getData(getFilesList(), false, this).get(position)).getName()))
                        .setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> {
                        })
                        .setPositiveButton(getString(R.string.install), (dialogInterface, i) -> SplitAPKInstaller.handleAppBundle(true, APKExplorer.getData(
                                getFilesList(), false, this).get(position), this)).show();
            } else if (APKExplorer.getData(getFilesList(), false, this).get(position).endsWith(".apk")) {
                if (Common.getAPKList().contains(APKExplorer.getData(getFilesList(), false, this).get(position))) {
                    Common.getAPKList().remove(APKExplorer.getData(getFilesList(), false, this).get(position));
                } else {
                    Common.getAPKList().add(APKExplorer.getData(getFilesList(), false, this).get(position));
                }
                mRecycleViewAdapter.notifyItemChanged(position);
                Common.getSelectCard().setVisibility(Common.getAPKList().isEmpty() ? View.GONE : View.VISIBLE);
            } else {
                sCommonUtils.snackBar(findViewById(android.R.id.content), getString(R.string.wrong_extension, ".apks/.apkm/.xapk")).show();
            }
        });

        Common.getSelectCard().setOnClickListener(v -> {
            if (APKData.findPackageName(this) != null) {
                if (Common.getAPKList().size() > 1) {
                    APKExplorer.handleAPKs(true, this);
                } else {
                    Intent intent = new Intent(this, APKInstallerActivity.class);
                    intent.putExtra("apkFilePath", Common.getAPKList().get(0));
                    startActivity(intent);
                    finish();
                }
            } else {
                sCommonUtils.snackBar(findViewById(android.R.id.content), getString(R.string.installation_status_bad_apks)).show();
            }
        });

        mSortButton.setOnClickListener(v -> {
            PopupMenu popupMenu = new PopupMenu(this, mSortButton);
            Menu menu = popupMenu.getMenu();
            menu.add(Menu.NONE, 0, Menu.NONE, getString(R.string.sort_order)).setCheckable(true)
                    .setChecked(sCommonUtils.getBoolean("az_order", true, this));
            popupMenu.setOnMenuItemClickListener(item -> {
                if (item.getItemId() == 0) {
                    sCommonUtils.saveBoolean("az_order", !sCommonUtils.getBoolean("az_order", true, this), this);
                    reload(this);
                }
                return false;
            });
            popupMenu.show();
        });
    }

    private File[] getFilesList() {
        if (!Common.getPath().endsWith(File.separator)) {
            Common.setPath(Common.getPath() + File.separator);
        }
        return new File(Common.getPath()).listFiles();
    }

    private void reload(Activity activity) {
        new sExecutor() {

            @Override
            public void onPreExecute() {
                APKExplorer.getData(getFilesList(), false, activity).clear();
                mProgressLayout.setVisibility(View.VISIBLE);
                mRecyclerView.setVisibility(View.GONE);
            }

            @Override
            public void doInBackground() {
                mRecycleViewAdapter = new InstallerFilePickerAdapter(APKExplorer.getData(getFilesList(), false, activity));
            }

            @Override
            public void onPostExecute() {
                mRecyclerView.setAdapter(mRecycleViewAdapter);
                if (getIntent().getStringExtra(TITLE_INTENT) != null) {
                    mTitle.setText(getIntent().getStringExtra(TITLE_INTENT));
                } else {
                    mTitle.setText(Common.getPath().equals(Environment.getExternalStorageDirectory().toString() + File.separator) ? getString(R.string.sdcard)
                            : new File(Common.getPath()).getName());
                }
                if (Common.getAPKList().isEmpty()) {
                    Common.getSelectCard().setVisibility(View.GONE);
                } else {
                    Common.getSelectCard().setVisibility(View.VISIBLE);
                }
                mRecyclerView.setVisibility(View.VISIBLE);
                mProgressLayout.setVisibility(View.GONE);
            }
        }.execute();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1 && Build.VERSION.SDK_INT < 30 && grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            this.recreate();
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        if (Common.isFinished()) {
            Common.setFinishStatus(false);
            finish();
        }
    }

    @Override
    public void onBackPressed() {
        if (Common.getPath().equals(getCacheDir().getPath() + "/splits/")) {
            new MaterialAlertDialogBuilder(this)
                    .setMessage(getString(R.string.installation_cancel_message))
                    .setNegativeButton(getString(R.string.cancel), (dialogInterface, i) -> {
                    })
                    .setPositiveButton(getString(R.string.yes), (dialogInterface, i) -> finish()).show();
        } else if (Common.getPath().equals(Environment.getExternalStorageDirectory().toString() + File.separator)) {
            super.onBackPressed();
        } else {
            Common.setPath(Objects.requireNonNull(new File(Common.getPath()).getParentFile()).getPath());
            Common.getAPKList().clear();
            reload(this);
        }
    }

}

app/src/main/java/com/threethan/questpatcher/utils/APKData.java
public class APKData {

    public static List<String> getData(Context context) {
        List<String> mData = new ArrayList<>();
        for (File mFile : getAPKList(context)) {
            if (sCommonUtils.getString("apkTypes", "apks", context).equals("bundles")) {
                if (mFile.exists() && mFile.isDirectory() && sFileUtils.exist(new File(mFile.toString(), "base.apk"))) {
                    if (Common.getSearchWord() == null) {
                        mData.add(mFile.getAbsolutePath());
                    } else if (Common.isTextMatched(mFile.getAbsolutePath(), Common.getSearchWord())) {
                        mData.add(mFile.getAbsolutePath());
                    }
                }
            } else {
                if (mFile.exists() && mFile.getName().endsWith(".apk")) {
                    if (Common.getSearchWord() == null) {
                        mData.add(mFile.getAbsolutePath());
                    } else if (sAPKUtils.getAPKName(mFile.getAbsolutePath(), context) != null && Common.isTextMatched(Objects.requireNonNull(sAPKUtils.getAPKName(
                            mFile.getAbsolutePath(), context)).toString(), Common.getSearchWord())) {
                        mData.add(mFile.getAbsolutePath());
                    } else if (Common.isTextMatched(mFile.getName(), Common.getSearchWord())) {
                        mData.add(mFile.getAbsolutePath());
                    }
                }
            }
        }
        Collections.sort(mData);
        if (!sCommonUtils.getBoolean("az_order", true, context)) {
            Collections.reverse(mData);
        }
        return mData;
    }

    private static File[] getAPKList(Context context) {
        if (!getExportAPKsPath(context).exists()) {
            sFileUtils.mkdir(getExportAPKsPath(context));
        }
        return getExportAPKsPath(context).listFiles();
    }

    public static File getExportAPKsPath(Context context) {
        if (Build.VERSION.SDK_INT < 29 && sCommonUtils.getString("exportAPKsPath", "externalFiles", context).equals("internalStorage")) {
            return new File(Environment.getExternalStorageDirectory(), "/AEE/exportedAPKs");
        } else {
            return context.getExternalFilesDir("");
        }
    }

    public static void signApks(File apk, File signedAPK, Context context) {
        try {
            checkAndPrepareSigningEnvironment(context);

            APKSigner apkSigner = new APKSigner(context);
            apkSigner.sign(apk, signedAPK);
        } catch (Exception ignored) {}
    }

    private static void checkAndPrepareSigningEnvironment(Context context) {
        File privateKey = new File(getSigningEnvironmentDir(context), "APKEditor.pk8");

        if (privateKey.exists()) {
            return;
        }

        sFileUtils.mkdir(getSigningEnvironmentDir(context));

        sFileUtils.copyAssetFile("APKEditor.pk8", privateKey, context);
    }

    private static File getSigningEnvironmentDir(Context context) {
        return new File(context.getFilesDir(), "signing");
    }

    private static String getParentFile(String path) {
        return Objects.requireNonNull(new File(path).getParentFile()).toString();
    }

    public static String findPackageName(Context context) {
        String name = null;
        for (String mAPKs : Common.getAPKList()) {
            if (sAPKUtils.getPackageName(mAPKs, context) != null) {
                name = Objects.requireNonNull(sAPKUtils.getPackageName(mAPKs, context));
            }
        }
        return name;
    }

    public static List<String> splitApks(String path) {
        List<String> list = new ArrayList<>();
        if (new File(path).getName().equals("base.apk") && new File(path).exists()) {
            for (File mFile : Objects.requireNonNull(new File(getParentFile(path)).listFiles())) {
                if (mFile.getName().endsWith(".apk")) {
                    list.add(mFile.getAbsolutePath());
                }
            }
        }
        return list;
    }

    public static boolean isAppBundle(String path) {
        return splitApks(path).size() > 1;
    }

    private static boolean fileToExclude(File file) {
        return file.isDirectory() && file.getName().equals(".aeeBackup") || file.isDirectory() && file.getName().equals(".aeeBuild")
                || file.isDirectory() && file.getName().equals("META-INF") || file.isDirectory() && file.getName().startsWith("classes")
                && file.getName().endsWith(".dex");
    }

    public static void shareFile(File file, String type, Context context) {
        Uri uriFile = FileProvider.getUriForFile(context,
                BuildConfig.APPLICATION_ID + ".provider", file);
        Intent share = new Intent(Intent.ACTION_SEND);
        share.setType(type);
        share.putExtra(Intent.EXTRA_TEXT, context.getString(R.string.share_summary, BuildConfig.VERSION_NAME));
        share.putExtra(Intent.EXTRA_STREAM, uriFile);
        share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        context.startActivity(Intent.createChooser(share, context.getString(R.string.share_with)));
    }

    @SuppressLint("StringFormatInvalid")
    public static void prepareSource(File buildDir, File exportPath, File backupPath, Context context) {
        if (!Common.isCancelled()) {
            for (File file : Objects.requireNonNull(exportPath.listFiles())) {
                if (file.isDirectory() && file.getName().startsWith("classes") && file.getName().endsWith(".dex")) {
                    // Build new dex file if the smali files are modified
                    if (APKExplorer.isSmaliEdited(new File(context.getCacheDir(), Common.getAppID() + "/.aeeBackup/appData").getAbsolutePath())) {
                        Common.setStatus(context.getString(R.string.building, file.getName()));
                        new SmaliToDex(file, new File(buildDir, file.getName()), 0, context).execute();
                    } else {
                        // Otherwise, use the original one from the backup folder
                        if (sFileUtils.exist(new File(backupPath, file.getName()))) {
                            sFileUtils.copy(new File(backupPath, file.getName()), new File(buildDir, file.getName()));
                        }
                    }
                } else if (file.isDirectory() && file.getName().equals("META-INF")) {
                    if (new File(file, "services").exists()) {
                        sFileUtils.copyDir(new File(file, "services"), new File(buildDir, "META-INF/services"));
                    }
                } else {
                    if (!fileToExclude(file)) {
                        if (file.isDirectory()) {
                            sFileUtils.copyDir(file, new File(buildDir, file.getName()));
                        } else {
                            sFileUtils.copy(file, new File(buildDir, file.getName()));
                        }
                    }
                }
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static void saveToDownload(File file, String name, Context context) {
        try {
            FileInputStream inputStream = new FileInputStream(file);
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, name);
            values.put(MediaStore.MediaColumns.MIME_TYPE, "*/*");
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
            Uri uri = context.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values);
            OutputStream outputStream = context.getContentResolver().openOutputStream(uri);
            sFileUtils.copyStream(inputStream, outputStream);
        } catch (IOException ignored) {
        }
    }

}

Answer: mSortButton.setOnClickListener(v -> {

<think>
The provided snippet ends with the closing of the mSearchButton click listener. In the APKsFragment, the next UI element to be configured is the sort button, which follows the same pattern of setting an OnClickListener. Therefore the next line of code is the start of that listener.
</think>
mSortButton.setOnClickListener(v -> {